Compare commits
23 Commits
v5.0.0-bet
...
v5.0.0-bet
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a48d7017ea | ||
![]() |
7d1f52ded4 | ||
![]() |
569adc1500 | ||
![]() |
e6eb193e8e | ||
![]() |
b8c63dade1 | ||
![]() |
82f92d36f1 | ||
![]() |
6b17c1febd | ||
![]() |
95882d1289 | ||
![]() |
70340bba7f | ||
![]() |
c809be9a07 | ||
![]() |
cc7b0f524e | ||
![]() |
a61784bb6c | ||
![]() |
3f92fc2ee5 | ||
![]() |
a4c08305c7 | ||
![]() |
067798ff2c | ||
![]() |
7a838fc8f9 | ||
![]() |
e669190ca2 | ||
![]() |
b84bb8630a | ||
![]() |
fb849be246 | ||
![]() |
382aa0f086 | ||
![]() |
303873974c | ||
![]() |
9f0ec46064 | ||
![]() |
9b2fa5d080 |
@@ -75,6 +75,11 @@ void Direction::UnserializeFrom(const gd::SerializerElement& element) {
|
||||
SetTimeBetweenFrames(
|
||||
element.GetDoubleAttribute("timeBetweenFrames", 1, "tempsEntre"));
|
||||
SetLoop(element.GetBoolAttribute("looping", false, "boucle"));
|
||||
#if defined(GD_IDE_ONLY)
|
||||
SetMetadata(element.HasAttribute("metadata")
|
||||
? element.GetStringAttribute("metadata")
|
||||
: "");
|
||||
#endif
|
||||
|
||||
const gd::SerializerElement& spritesElement =
|
||||
element.GetChild("sprites", 0, "Sprites");
|
||||
@@ -182,6 +187,7 @@ void SaveSpritesDirection(const vector<Sprite>& sprites,
|
||||
void Direction::SerializeTo(gd::SerializerElement& element) const {
|
||||
element.SetAttribute("looping", IsLooping());
|
||||
element.SetAttribute("timeBetweenFrames", GetTimeBetweenFrames());
|
||||
if (!GetMetadata().empty()) element.SetAttribute("metadata", GetMetadata());
|
||||
SaveSpritesDirection(sprites, element.AddChild("sprites"));
|
||||
}
|
||||
#endif
|
||||
|
@@ -6,17 +6,16 @@
|
||||
#ifndef GDCORE_DIRECTION_H
|
||||
#define GDCORE_DIRECTION_H
|
||||
#include <vector>
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class Sprite;
|
||||
}
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Class defining a direction of an Animation.
|
||||
* \brief Class defining a direction (set of frames) of an Animation.
|
||||
*
|
||||
* \see SpriteObject
|
||||
* \see Animation
|
||||
@@ -32,78 +31,101 @@ class GD_CORE_API Direction {
|
||||
virtual ~Direction();
|
||||
|
||||
/**
|
||||
* Return true if sprites looping is activated
|
||||
* \brief Return true if sprites looping is activated
|
||||
*/
|
||||
inline bool IsLooping() const { return loop; }
|
||||
|
||||
/**
|
||||
* Set if the sprites must be looping or not.
|
||||
* \brief Set if the sprites must be looping or not.
|
||||
*/
|
||||
void SetLoop(bool loop_);
|
||||
|
||||
/**
|
||||
* Get the time between each sprite
|
||||
* \brief Get the time between each sprite
|
||||
*/
|
||||
inline float GetTimeBetweenFrames() const { return timeBetweenFrame; }
|
||||
|
||||
/**
|
||||
* Set the time between each sprite
|
||||
* \brief Set the time between each sprite
|
||||
*
|
||||
* \param time Time between each sprite, in seconds.
|
||||
*/
|
||||
void SetTimeBetweenFrames(float time);
|
||||
|
||||
/**
|
||||
* Return a reference to a sprite of the direction.
|
||||
* \brief Return a reference to a sprite of the direction.
|
||||
*
|
||||
* \param nb The index of the sprite to be accessed. Bound checking is not
|
||||
* made. \return A reference to the sprite.
|
||||
* made.
|
||||
*
|
||||
* \return A reference to the sprite.
|
||||
*/
|
||||
const Sprite& GetSprite(std::size_t nb) const;
|
||||
|
||||
/**
|
||||
* Return a reference to a sprite of the direction.
|
||||
* \brief Return a reference to a sprite of the direction.
|
||||
*
|
||||
* \param nb The index of the sprite to be accessed. Bound checking is not
|
||||
* made. \return A reference to the sprite.
|
||||
* made.
|
||||
*
|
||||
* \return A reference to the sprite.
|
||||
*/
|
||||
Sprite& GetSprite(std::size_t nb);
|
||||
|
||||
/**
|
||||
* Check if the direction contains sprites.
|
||||
* \brief Check if the direction contains sprites.
|
||||
*
|
||||
* \return true if the direction does not have any sprite.
|
||||
*/
|
||||
bool HasNoSprites() const;
|
||||
|
||||
/**
|
||||
* Return the number of sprite used in the direction
|
||||
* \brief Return the number of sprite used in the direction
|
||||
*
|
||||
* \return The number of sprite used in the direction
|
||||
*/
|
||||
std::size_t GetSpritesCount() const;
|
||||
|
||||
/**
|
||||
* Remove the sprite at the specified position.
|
||||
* \brief Remove the sprite at the specified position.
|
||||
*
|
||||
* Bound-checking is made.
|
||||
*/
|
||||
void RemoveSprite(std::size_t index);
|
||||
|
||||
/**
|
||||
* Clear the direction from all of its sprites
|
||||
* \brief Clear the direction from all of its sprites
|
||||
*/
|
||||
void RemoveAllSprites();
|
||||
|
||||
/**
|
||||
* Add a new sprite at the end of the list.
|
||||
* \brief Add a new sprite at the end of the list.
|
||||
*/
|
||||
void AddSprite(const Sprite& sprite);
|
||||
|
||||
/**
|
||||
* Swap the position of two sprites
|
||||
* \brief Swap the position of two sprites
|
||||
*/
|
||||
void SwapSprites(std::size_t firstSpriteIndex, std::size_t secondSpriteIndex);
|
||||
|
||||
/**
|
||||
* Change the position of the specified sprite.
|
||||
* \brief Change the position of the specified sprite.
|
||||
*/
|
||||
void MoveSprite(std::size_t oldIndex, std::size_t newIndex);
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Set the metadata (any string) associated to the Direction.
|
||||
* \note Can be used by external editors to store extra information.
|
||||
*/
|
||||
virtual void SetMetadata(const gd::String& metadata_) { metadata = metadata_; }
|
||||
|
||||
/**
|
||||
* \brief Return the (optional) metadata associated to the Direction.
|
||||
*/
|
||||
virtual const gd::String& GetMetadata() const { return metadata; }
|
||||
#endif
|
||||
|
||||
void UnserializeFrom(const gd::SerializerElement& element);
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void SerializeTo(gd::SerializerElement& element) const;
|
||||
@@ -113,6 +135,9 @@ class GD_CORE_API Direction {
|
||||
bool loop; ///< true if the animation must loop.
|
||||
float timeBetweenFrame; ///< The time between each sprite of the animation.
|
||||
std::vector<Sprite> sprites; ///< The sprites of the direction.
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::String metadata;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -49,11 +49,25 @@ void ResourcesMergingHelper::SetNewFilename(gd::String oldFilename,
|
||||
gd::String newFilename) {
|
||||
if (oldFilenames.find(oldFilename) != oldFilenames.end()) return;
|
||||
|
||||
// Make sure that the new filename is not already used.
|
||||
gd::String finalFilename = gd::NewNameGenerator::Generate(
|
||||
newFilename, [this](const gd::String& name) {
|
||||
return newFilenames.find(name) != newFilenames.end();
|
||||
});
|
||||
// Extract baseName and extension from the new filename
|
||||
size_t extensionPos = newFilename.find_last_of(".");
|
||||
gd::String extension =
|
||||
extensionPos != gd::String::npos
|
||||
? newFilename.substr(extensionPos, newFilename.length())
|
||||
: "";
|
||||
gd::String baseName = newFilename.substr(0, extensionPos);
|
||||
|
||||
// Make sure that the new filename is not already used. Generate a
|
||||
// new filename while there is a collision.
|
||||
// Preserving extension is important.
|
||||
gd::String finalFilename =
|
||||
gd::NewNameGenerator::Generate(
|
||||
baseName,
|
||||
[this, extension](const gd::String& newBaseName) {
|
||||
return newFilenames.find(newBaseName + extension) !=
|
||||
newFilenames.end();
|
||||
}) +
|
||||
extension;
|
||||
|
||||
oldFilenames[oldFilename] = finalFilename;
|
||||
newFilenames[finalFilename] = oldFilename;
|
||||
|
@@ -18,8 +18,10 @@ class AbstractFileSystem;
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief ResourcesMergingHelper is used (mainly during compilation) so
|
||||
* as to inventory resources and change their filenames
|
||||
* \brief ResourcesMergingHelper is used (mainly during export)
|
||||
* to list resources and generate new filenames, to allow them to be all copied
|
||||
* in a single directory (potentially changing the filename to avoid conflicts,
|
||||
* but preserving extensions).
|
||||
*
|
||||
* \see ArbitraryResourceWorker
|
||||
*
|
||||
@@ -82,9 +84,9 @@ class GD_CORE_API ResourcesMergingHelper : public ArbitraryResourceWorker {
|
||||
///< baseDirectory, will be preserved in
|
||||
///< filenames.
|
||||
bool preserveAbsoluteFilenames; ///< If set to true, the filenames which are
|
||||
///< absolute ( C:\MyFile.png ) will not be
|
||||
///< transformed into their filenames (
|
||||
///< MyFile.png ).
|
||||
///< absolute (C:\MyFile.png will not be
|
||||
///< transformed into a relative filename
|
||||
///< (MyFile.png).
|
||||
gd::AbstractFileSystem&
|
||||
fs; ///< The gd::AbstractFileSystem used to manipulate files.
|
||||
};
|
||||
|
@@ -65,6 +65,7 @@ Project::Project()
|
||||
version("1.0.0"),
|
||||
packageName("com.example.gamename"),
|
||||
orientation("landscape"),
|
||||
adMobAppId(""),
|
||||
folderProject(false),
|
||||
#endif
|
||||
windowWidth(800),
|
||||
@@ -640,6 +641,7 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
SetAuthor(propElement.GetChild("author", 0, "Auteur").GetValue().GetString());
|
||||
SetPackageName(propElement.GetStringAttribute("packageName"));
|
||||
SetOrientation(propElement.GetStringAttribute("orientation", "default"));
|
||||
SetAdMobAppId(propElement.GetStringAttribute("adMobAppId", ""));
|
||||
SetFolderProject(propElement.GetBoolAttribute("folderProject"));
|
||||
SetProjectFile(propElement.GetStringAttribute("projectFile"));
|
||||
SetLastCompilationDirectory(propElement
|
||||
@@ -916,6 +918,7 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
propElement.SetAttribute("folderProject", folderProject);
|
||||
propElement.SetAttribute("packageName", packageName);
|
||||
propElement.SetAttribute("orientation", orientation);
|
||||
propElement.SetAttribute("adMobAppId", adMobAppId);
|
||||
platformSpecificAssets.SerializeTo(
|
||||
propElement.AddChild("platformSpecificAssets"));
|
||||
loadingScreen.SerializeTo(propElement.AddChild("loadingScreen"));
|
||||
@@ -1251,6 +1254,7 @@ void Project::Init(const gd::Project& game) {
|
||||
author = game.author;
|
||||
packageName = game.packageName;
|
||||
orientation = game.orientation;
|
||||
adMobAppId = game.adMobAppId;
|
||||
folderProject = game.folderProject;
|
||||
latestCompilationDirectory = game.latestCompilationDirectory;
|
||||
platformSpecificAssets = game.platformSpecificAssets;
|
||||
|
@@ -116,6 +116,20 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
const gd::String& GetOrientation() const { return orientation; }
|
||||
|
||||
/**
|
||||
* \brief Change the project AdMob application ID (needed
|
||||
* to use the AdMob extension). This has no effect on desktop
|
||||
* and web browsers.
|
||||
*/
|
||||
void SetAdMobAppId(const gd::String& adMobAppId_) {
|
||||
adMobAppId = adMobAppId_;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get the project AdMob application ID.
|
||||
*/
|
||||
const gd::String& GetAdMobAppId() const { return adMobAppId; }
|
||||
|
||||
/**
|
||||
* Called when project file has changed.
|
||||
*/
|
||||
@@ -962,6 +976,7 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
gd::String packageName; ///< Game package name
|
||||
gd::String orientation; ///< Lock game orientation (on mobile devices).
|
||||
///< "default", "landscape" or "portrait".
|
||||
gd::String adMobAppId; ///< AdMob application ID.
|
||||
bool
|
||||
folderProject; ///< True if folder project, false if single file project.
|
||||
gd::String gameFile; ///< File of the game
|
||||
|
361
Extensions/AdMob/JsExtension.js
Normal file
@@ -0,0 +1,361 @@
|
||||
/**
|
||||
* This is a declaration of an extension for GDevelop 5.
|
||||
*
|
||||
* ℹ️ Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change
|
||||
* to this extension file or to any other *.js file that you reference inside.
|
||||
*
|
||||
* The file must be named "JsExtension.js", otherwise GDevelop won't load it.
|
||||
* ⚠️ If you make a change and the extension is not loaded, open the developer console
|
||||
* and search for any errors.
|
||||
*
|
||||
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
|
||||
*/
|
||||
module.exports = {
|
||||
createExtension: function(t, gd) {
|
||||
const extension = new gd.PlatformExtension();
|
||||
extension.setExtensionInformation(
|
||||
"AdMob",
|
||||
t("AdMob"),
|
||||
t(
|
||||
"Allow the game to display AdMob banner, interstitial and reward video ads"
|
||||
),
|
||||
"Franco Maciel",
|
||||
"MIT"
|
||||
);
|
||||
|
||||
// Banner
|
||||
extension
|
||||
.addCondition(
|
||||
"BannerLoading",
|
||||
t("Banner loading"),
|
||||
t("Check if a banner is currently loading."),
|
||||
t("Banner is loading"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.isBannerLoading");
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
"BannerReady",
|
||||
t("Banner ready"),
|
||||
t("Check if a banner is ready to be displayed."),
|
||||
t("Banner is ready"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.isBannerReady");
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
"BannerShowing",
|
||||
t("Banner showing"),
|
||||
t("Check if there is a banner being displayed."),
|
||||
t("Banner is showing"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.isBannerShowing");
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
"BannerExists",
|
||||
t("Banner exists"),
|
||||
t("Check if there is a banner in memory (visible or hidden)."),
|
||||
t("Banner exists"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.existBanner");
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
"LoadBanner",
|
||||
t("Load banner"),
|
||||
t(
|
||||
"Start loading a banner, you can display it automatically when finish loading.\nIf test mode is set to true a test banner will be displayed."
|
||||
),
|
||||
t(
|
||||
"Load banner (at top: _PARAM2_, overlap: _PARAM3_, show on load: _PARAM4_, test mode: _PARAM5_)"
|
||||
),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.addParameter("string", t("Android banner ID"), "", false)
|
||||
.addParameter("string", t("iOS banner ID"), "", false)
|
||||
.addParameter(
|
||||
"yesorno",
|
||||
t("Display at top? (bottom otherwise)"),
|
||||
"",
|
||||
false
|
||||
)
|
||||
.setDefaultValue("false")
|
||||
.addParameter("yesorno", t("Overlap webview?"), "", false)
|
||||
.setDefaultValue("true")
|
||||
.addParameter("yesorno", t("Display on load complete?"), "", false)
|
||||
.setDefaultValue("true")
|
||||
.addParameter("yesorno", t("Test mode?"), "", false)
|
||||
.setDefaultValue("true")
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.loadBanner");
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
"ShowBanner",
|
||||
t("Show banner"),
|
||||
t("Show the banner, will work only when the banner is fully loaded."),
|
||||
t("Show banner"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.showBanner");
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
"HideBanner",
|
||||
t("Hide banner"),
|
||||
t(
|
||||
"Hide the banner. You can show it again with the corresponding action."
|
||||
),
|
||||
t("Hide banner"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.hideBanner");
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
"RemoveBanner",
|
||||
t("Remove banner"),
|
||||
t(
|
||||
"Remove the banner. You have to load another banner to show it again."
|
||||
),
|
||||
t("Remove banner"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.removeBanner");
|
||||
|
||||
// Interstitial
|
||||
extension
|
||||
.addCondition(
|
||||
"InterstitialLoading",
|
||||
t("Interstitial loading"),
|
||||
t("Check if an interstitial is currently loading."),
|
||||
t("Interstitial is loading"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.isInterstitialLoading");
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
"InterstitialReady",
|
||||
t("Interstitial ready"),
|
||||
t("Check if an interstitial is ready to be displayed."),
|
||||
t("Interstitial is ready"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.isInterstitialReady");
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
"InterstitialShowing",
|
||||
t("Interstitial showing"),
|
||||
t("Check if there is an interstitial being displayed."),
|
||||
t("Interstitial is showing"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.isInterstitialShowing");
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
"LoadInterstitial",
|
||||
t("Load interstitial"),
|
||||
t(
|
||||
"Start loading an interstitial, you can display it automatically when finish loading.\nIf test mode is set to true a test interstitial will be displayed."
|
||||
),
|
||||
t("Load interstitial (show on load: _PARAM2_, test mode: _PARAM3_)"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.addParameter("string", t("Android interstitial ID"), "", false)
|
||||
.addParameter("string", t("iOS interstitial ID"), "", false)
|
||||
.addParameter("yesorno", t("Display on load complete?"), "", false)
|
||||
.setDefaultValue("true")
|
||||
.addParameter("yesorno", t("Test mode?"), "", false)
|
||||
.setDefaultValue("true")
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.loadInterstitial");
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
"ShowInterstitial",
|
||||
t("Show interstitial"),
|
||||
t(
|
||||
"Show the interstitial, will work only when the interstitial is fully loaded."
|
||||
),
|
||||
t("Show interstitial"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.showInterstitial");
|
||||
|
||||
// Reward video
|
||||
extension
|
||||
.addCondition(
|
||||
"VideoLoading",
|
||||
t("Video loading"),
|
||||
t("Check if a reward video is currently loading."),
|
||||
t("Reward video is loading"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.isVideoLoading");
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
"VideoReady",
|
||||
t("Video ready"),
|
||||
t("Check if a reward video is ready to be displayed."),
|
||||
t("Reward video is ready"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.isVideoReady");
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
"VideoShowing",
|
||||
t("Video showing"),
|
||||
t("Check if there is a reward video being displayed."),
|
||||
t("Reward video is showing"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.isVideoShowing");
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
"VideoReward",
|
||||
t("Video reward"),
|
||||
t(
|
||||
"Check if there is a video reward.\nYou can mark it as non-claimed yet, so you can check this reward in other events."
|
||||
),
|
||||
t("Video reward given"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.addParameter("yesorno", t("Mark as claimed"), "", false)
|
||||
.setDefaultValue("true")
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.existVideoReward");
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
"LoadVideo",
|
||||
t("Load video"),
|
||||
t(
|
||||
"Start loading a reward video, you can display it automatically when finish loading.\nIf test mode is set to true a test video will be displayed."
|
||||
),
|
||||
t("Load reward video (show on load: _PARAM2_, test mode: _PARAM3_)"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.addParameter("string", t("Android reward video ID"), "", false)
|
||||
.addParameter("string", t("iOS reward video ID"), "", false)
|
||||
.addParameter("yesorno", t("Display on load complete?"), "", false)
|
||||
.setDefaultValue("true")
|
||||
.addParameter("yesorno", t("Test mode?"), "", false)
|
||||
.setDefaultValue("true")
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.loadVideo");
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
"ShowVideo",
|
||||
t("Show video"),
|
||||
t(
|
||||
"Show the reward video, will work only when the video is fully loaded."
|
||||
),
|
||||
t("Show reward video"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.showVideo");
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
"ClaimReward",
|
||||
t("Claim reward"),
|
||||
t("Mark the video reward as claimed."),
|
||||
t("Claim video reward"),
|
||||
t("AdMob"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png"
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile("Extensions/AdMob/admobtools.js")
|
||||
.setFunctionName("gdjs.adMob.claimVideoReward");
|
||||
|
||||
return extension;
|
||||
},
|
||||
runExtensionSanityTests: function(gd, extension) {
|
||||
return [];
|
||||
}
|
||||
};
|
331
Extensions/AdMob/admobtools.js
Normal file
@@ -0,0 +1,331 @@
|
||||
/**
|
||||
* @memberof gdjs
|
||||
* @class adMob
|
||||
* @static
|
||||
* @private
|
||||
*/
|
||||
gdjs.adMob = {
|
||||
// Banner
|
||||
bannerLoading: false,
|
||||
bannerReady: false,
|
||||
bannerShowing: false,
|
||||
bannerExists: false,
|
||||
bannerAutoshow: false, // Needed because the banner event listeners bug
|
||||
// Interstitial
|
||||
interstitialLoading: false,
|
||||
interstitialReady: false,
|
||||
interstitialShowing: false,
|
||||
// Reward video
|
||||
videoLoading: false,
|
||||
videoReady: false,
|
||||
videoShowing: false,
|
||||
videoReward: false
|
||||
};
|
||||
|
||||
gdjs.adMob._getPlatformName = function() {
|
||||
if (/(android)/i.test(navigator.userAgent)) {
|
||||
return "android";
|
||||
} else if (/(ipod|iphone|ipad)/i.test(navigator.userAgent)) {
|
||||
return "ios";
|
||||
} else {
|
||||
return "windowsPhone";
|
||||
}
|
||||
};
|
||||
|
||||
// Banner
|
||||
gdjs.adMob.isBannerLoading = function() {
|
||||
return gdjs.adMob.bannerLoading;
|
||||
};
|
||||
|
||||
gdjs.adMob.isBannerReady = function() {
|
||||
// This block is needed because the banner event listeners bug
|
||||
if (gdjs.adMob.bannerAutoshow && gdjs.adMob.bannerReady) {
|
||||
gdjs.adMob.bannerReady = false;
|
||||
gdjs.adMob.bannerShowing = true;
|
||||
gdjs.adMob.bannerExists = true;
|
||||
}
|
||||
|
||||
return gdjs.adMob.bannerReady;
|
||||
};
|
||||
|
||||
gdjs.adMob.isBannerShowing = function() {
|
||||
// This block is needed because the banner event listeners bug
|
||||
if (gdjs.adMob.bannerAutoshow && gdjs.adMob.bannerReady) {
|
||||
gdjs.adMob.bannerReady = false;
|
||||
gdjs.adMob.bannerShowing = true;
|
||||
gdjs.adMob.bannerExists = true;
|
||||
}
|
||||
|
||||
return gdjs.adMob.bannerShowing;
|
||||
};
|
||||
|
||||
gdjs.adMob.existBanner = function() {
|
||||
// This block is needed because the banner event listeners bug
|
||||
if (gdjs.adMob.bannerAutoshow && gdjs.adMob.bannerReady) {
|
||||
gdjs.adMob.bannerReady = false;
|
||||
gdjs.adMob.bannerShowing = true;
|
||||
gdjs.adMob.bannerExists = true;
|
||||
}
|
||||
|
||||
return gdjs.adMob.bannerExists;
|
||||
};
|
||||
|
||||
gdjs.adMob.loadBanner = function(
|
||||
androidID,
|
||||
iosID,
|
||||
atTop,
|
||||
overlap,
|
||||
displayOnLoading,
|
||||
testMode
|
||||
) {
|
||||
if (typeof admob === "undefined") return;
|
||||
|
||||
admob.banner.config({
|
||||
id: gdjs.adMob._getPlatformName() === "android" ? androidID : iosID, // Support Android & iOS
|
||||
bannerAtTop: atTop,
|
||||
overlap: overlap,
|
||||
autoShow: displayOnLoading,
|
||||
isTesting: testMode
|
||||
});
|
||||
admob.banner.prepare();
|
||||
|
||||
gdjs.adMob.bannerLoading = true;
|
||||
gdjs.adMob.bannerReady = false;
|
||||
|
||||
// These lines are needed because the banner event listeners bug
|
||||
gdjs.adMob.bannerAutoshow = displayOnLoading;
|
||||
gdjs.adMob.bannerShowing = false;
|
||||
gdjs.adMob.bannerExists = false;
|
||||
};
|
||||
|
||||
gdjs.adMob.showBanner = function() {
|
||||
if (typeof admob === "undefined") return;
|
||||
|
||||
// This block is needed because the banner event listeners bug
|
||||
if (gdjs.adMob.bannerReady) {
|
||||
gdjs.adMob.bannerReady = false;
|
||||
gdjs.adMob.bannerExists = true;
|
||||
}
|
||||
|
||||
if (gdjs.adMob.bannerExists) gdjs.adMob.bannerShowing = true;
|
||||
|
||||
admob.banner.show();
|
||||
};
|
||||
|
||||
gdjs.adMob.hideBanner = function() {
|
||||
if (typeof admob === "undefined") return;
|
||||
|
||||
if (gdjs.adMob.bannerExists) gdjs.adMob.bannerShowing = false;
|
||||
|
||||
admob.banner.hide();
|
||||
};
|
||||
|
||||
gdjs.adMob.removeBanner = function() {
|
||||
if (typeof admob === "undefined") return;
|
||||
|
||||
// These lines are needed because the banner event listeners bug
|
||||
gdjs.adMob.bannerExists = false;
|
||||
gdjs.adMob.bannerShowing = false;
|
||||
|
||||
admob.banner.remove();
|
||||
};
|
||||
|
||||
// Interstitial
|
||||
gdjs.adMob.isInterstitialLoading = function() {
|
||||
return gdjs.adMob.interstitialLoading;
|
||||
};
|
||||
|
||||
gdjs.adMob.isInterstitialReady = function() {
|
||||
return gdjs.adMob.interstitialReady;
|
||||
};
|
||||
|
||||
gdjs.adMob.isInterstitialShowing = function() {
|
||||
return gdjs.adMob.interstitialShowing;
|
||||
};
|
||||
|
||||
gdjs.adMob.loadInterstitial = function(
|
||||
androidID,
|
||||
iosID,
|
||||
displayOnLoading,
|
||||
testMode
|
||||
) {
|
||||
if (typeof admob === "undefined") return;
|
||||
|
||||
admob.interstitial.config({
|
||||
id: gdjs.adMob._getPlatformName() === "android" ? androidID : iosID, // Support Android & iOS
|
||||
autoShow: displayOnLoading,
|
||||
isTesting: testMode
|
||||
});
|
||||
admob.interstitial.prepare();
|
||||
|
||||
gdjs.adMob.interstitialLoading = true;
|
||||
gdjs.adMob.interstitialReady = false;
|
||||
};
|
||||
|
||||
gdjs.adMob.showInterstitial = function() {
|
||||
if (typeof admob === "undefined") return;
|
||||
|
||||
admob.interstitial.show();
|
||||
};
|
||||
|
||||
// Reward video
|
||||
gdjs.adMob.isVideoLoading = function() {
|
||||
return gdjs.adMob.videoLoading;
|
||||
};
|
||||
|
||||
gdjs.adMob.isVideoReady = function() {
|
||||
return gdjs.adMob.videoReady;
|
||||
};
|
||||
|
||||
gdjs.adMob.isVideoShowing = function() {
|
||||
return gdjs.adMob.videoShowing;
|
||||
};
|
||||
|
||||
gdjs.adMob.existVideoReward = function(markAsClaimed) {
|
||||
var reward = gdjs.adMob.videoReward;
|
||||
if (markAsClaimed) gdjs.adMob.videoReward = false;
|
||||
|
||||
return reward;
|
||||
};
|
||||
|
||||
gdjs.adMob.loadVideo = function(androidID, iosID, displayOnLoading, testMode) {
|
||||
if (typeof admob === "undefined") return;
|
||||
|
||||
admob.rewardvideo.config({
|
||||
id: gdjs.adMob._getPlatformName() === "android" ? androidID : iosID, // Support Android & iOS
|
||||
autoShow: displayOnLoading,
|
||||
isTesting: testMode
|
||||
});
|
||||
admob.rewardvideo.prepare();
|
||||
|
||||
gdjs.adMob.videoLoading = true;
|
||||
gdjs.adMob.videoReady = false;
|
||||
};
|
||||
|
||||
gdjs.adMob.showVideo = function() {
|
||||
if (typeof admob === "undefined") return;
|
||||
|
||||
admob.rewardvideo.show();
|
||||
};
|
||||
|
||||
gdjs.adMob.claimVideoReward = function() {
|
||||
gdjs.adMob.videoReward = false;
|
||||
};
|
||||
|
||||
// Banner event listeners
|
||||
document.addEventListener(
|
||||
"admob.banner.events.LOAD",
|
||||
function() {
|
||||
gdjs.adMob.bannerReady = true;
|
||||
gdjs.adMob.bannerLoading = false;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
document.addEventListener(
|
||||
"admob.banner.events.LOAD_FAIL",
|
||||
function() {
|
||||
gdjs.adMob.bannerLoading = false;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// BUG: These two never get called
|
||||
/*
|
||||
document.addEventListener(
|
||||
"admob.banner.events.OPEN",
|
||||
function() {
|
||||
gdjs.adMob.bannerExists = true;
|
||||
gdjs.adMob.bannerShowing = true;
|
||||
gdjs.adMob.bannerReady = false;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
document.addEventListener(
|
||||
"admob.banner.events.CLOSE",
|
||||
function() {
|
||||
gdjs.adMob.bannerExists = false;
|
||||
gdjs.adMob.bannerShowing = false;
|
||||
},
|
||||
false
|
||||
);
|
||||
*/
|
||||
|
||||
// Interstitial event listeners
|
||||
document.addEventListener(
|
||||
"admob.interstitial.events.LOAD",
|
||||
function() {
|
||||
gdjs.adMob.interstitialReady = true;
|
||||
gdjs.adMob.interstitialLoading = false;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
document.addEventListener(
|
||||
"admob.interstitial.events.LOAD_FAIL",
|
||||
function() {
|
||||
gdjs.adMob.interstitialLoading = false;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
document.addEventListener(
|
||||
"admob.interstitial.events.OPEN",
|
||||
function() {
|
||||
gdjs.adMob.interstitialShowing = true;
|
||||
gdjs.adMob.interstitialReady = false;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
document.addEventListener(
|
||||
"admob.interstitial.events.CLOSE",
|
||||
function() {
|
||||
gdjs.adMob.interstitialShowing = false;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// Reward video event listeners
|
||||
document.addEventListener(
|
||||
"admob.rewardvideo.events.LOAD",
|
||||
function() {
|
||||
gdjs.adMob.videoReady = true;
|
||||
gdjs.adMob.videoLoading = false;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
document.addEventListener(
|
||||
"admob.rewardvideo.events.LOAD_FAIL",
|
||||
function() {
|
||||
gdjs.adMob.videoLoading = false;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
document.addEventListener(
|
||||
"admob.rewardvideo.events.OPEN",
|
||||
function() {
|
||||
gdjs.adMob.videoShowing = true;
|
||||
gdjs.adMob.videoReady = false;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
document.addEventListener(
|
||||
"admob.rewardvideo.events.CLOSE",
|
||||
function() {
|
||||
gdjs.adMob.videoShowing = false;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
document.addEventListener(
|
||||
"admob.rewardvideo.events.REWARD",
|
||||
function() {
|
||||
gdjs.adMob.videoReward = true;
|
||||
},
|
||||
false
|
||||
);
|
@@ -1,117 +0,0 @@
|
||||
/**
|
||||
|
||||
GDevelop - AdMob Object Extension
|
||||
Copyright (c) 2008-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "AdMobObject.h"
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include "GDCore/IDE/Dialogs/PropertyDescriptor.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCpp/Runtime/CommonTools.h"
|
||||
#include "GDCpp/Runtime/ImageManager.h"
|
||||
#include "GDCpp/Runtime/Project/InitialInstance.h"
|
||||
#include "GDCpp/Runtime/Project/Object.h"
|
||||
#include "GDCpp/Runtime/Serialization/SerializerElement.h"
|
||||
|
||||
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
|
||||
#include <wx/bitmap.h>
|
||||
|
||||
sf::Texture AdMobObject::edittimeIconImage;
|
||||
sf::Sprite AdMobObject::edittimeIcon;
|
||||
#endif
|
||||
|
||||
AdMobObject::AdMobObject(gd::String name_)
|
||||
: Object(name_), isTesting(true), overlap(true), showOnStartup(true) {}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> AdMobObject::GetProperties(
|
||||
gd::Project& project) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties[_("Banner ID (Android)")].SetValue(androidBannerId);
|
||||
properties[_("Interstitial ID (Android)")].SetValue(androidInterstitialId);
|
||||
properties[_("Banner ID (iOS)")].SetValue(iosBannerId);
|
||||
properties[_("Interstitial ID (iOS)")].SetValue(iosInterstitialId);
|
||||
properties[_("Testing mode")]
|
||||
.SetValue(isTesting ? "true" : "false")
|
||||
.SetType("Boolean");
|
||||
properties[_("Overlap game")]
|
||||
.SetValue(overlap ? "true" : "false")
|
||||
.SetType("Boolean");
|
||||
properties[_("Show banner on startup")]
|
||||
.SetValue(showOnStartup ? "true" : "false")
|
||||
.SetType("Boolean");
|
||||
properties[_("Banner position")]
|
||||
.SetValue(position == "Bottom" ? _("Bottom of the screen")
|
||||
: _("Top of the screen"))
|
||||
.SetType("Choice")
|
||||
.AddExtraInfo(_("Top of the screen"))
|
||||
.AddExtraInfo(_("Bottom of the screen"));
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
bool AdMobObject::UpdateProperty(const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project) {
|
||||
if (name == _("Banner ID (Android)")) androidBannerId = value;
|
||||
if (name == _("Interstitial ID (Android)")) androidInterstitialId = value;
|
||||
if (name == _("Banner ID (iOS)")) iosBannerId = value;
|
||||
if (name == _("Interstitial ID (iOS)")) iosInterstitialId = value;
|
||||
if (name == _("Testing mode")) isTesting = value == "1";
|
||||
if (name == _("Overlap game")) overlap = value == "1";
|
||||
if (name == _("Show banner on startup")) showOnStartup = value == "1";
|
||||
if (name == _("Banner position"))
|
||||
position = value == _("Top of the screen") ? "Top" : "Bottom";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AdMobObject::DoUnserializeFrom(gd::Project& project,
|
||||
const gd::SerializerElement& element) {
|
||||
androidBannerId = element.GetStringAttribute("androidBannerId");
|
||||
androidInterstitialId = element.GetStringAttribute("androidInterstitialId");
|
||||
iosBannerId = element.GetStringAttribute("iosBannerId");
|
||||
iosInterstitialId = element.GetStringAttribute("iosInterstitialId");
|
||||
position = element.GetStringAttribute("position");
|
||||
isTesting = element.GetBoolAttribute("isTesting");
|
||||
overlap = element.GetBoolAttribute("overlap");
|
||||
showOnStartup = element.GetBoolAttribute("showOnStartup");
|
||||
}
|
||||
|
||||
void AdMobObject::DoSerializeTo(gd::SerializerElement& element) const {
|
||||
element.SetAttribute("androidBannerId", androidBannerId);
|
||||
element.SetAttribute("androidInterstitialId", androidInterstitialId);
|
||||
element.SetAttribute("iosBannerId", iosBannerId);
|
||||
element.SetAttribute("iosInterstitialId", iosInterstitialId);
|
||||
element.SetAttribute("position", position);
|
||||
element.SetAttribute("isTesting", isTesting);
|
||||
element.SetAttribute("overlap", overlap);
|
||||
element.SetAttribute("showOnStartup", showOnStartup);
|
||||
}
|
||||
|
||||
#if !defined(GD_NO_WX_GUI)
|
||||
void AdMobObject::DrawInitialInstance(gd::InitialInstance& instance,
|
||||
sf::RenderTarget& renderTarget,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout) {
|
||||
edittimeIcon.setPosition(instance.GetX(), instance.GetY());
|
||||
renderTarget.draw(edittimeIcon);
|
||||
}
|
||||
|
||||
void AdMobObject::LoadEdittimeIcon() {
|
||||
edittimeIconImage.loadFromFile("JsPlatform/Extensions/admobicon.png");
|
||||
edittimeIcon.setTexture(edittimeIconImage);
|
||||
}
|
||||
|
||||
bool AdMobObject::GenerateThumbnail(const gd::Project& project,
|
||||
wxBitmap& thumbnail) const {
|
||||
thumbnail =
|
||||
wxBitmap("JsPlatform/Extensions/admobicon24.png", wxBITMAP_TYPE_ANY);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
gd::Object* CreateAdMobObject(gd::String name) { return new AdMobObject(name); }
|
@@ -1,73 +0,0 @@
|
||||
/**
|
||||
|
||||
GDevelop - AdMob Object Extension
|
||||
Copyright (c) 2008-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef ADMOBOBJECT_H
|
||||
#define ADMOBOBJECT_H
|
||||
|
||||
#include "GDCpp/Runtime/Project/Object.h"
|
||||
#include "GDCpp/Runtime/String.h"
|
||||
namespace gd {
|
||||
class InitialInstance;
|
||||
}
|
||||
namespace gd {
|
||||
class Project;
|
||||
}
|
||||
namespace sf {
|
||||
class Texture;
|
||||
}
|
||||
namespace sf {
|
||||
class Sprite;
|
||||
}
|
||||
class wxBitmap;
|
||||
|
||||
class GD_EXTENSION_API AdMobObject : public gd::Object {
|
||||
public:
|
||||
AdMobObject(gd::String name_);
|
||||
virtual ~AdMobObject(){};
|
||||
virtual std::unique_ptr<gd::Object> Clone() const override {
|
||||
return gd::make_unique<AdMobObject>(*this);
|
||||
}
|
||||
|
||||
#if !defined(GD_NO_WX_GUI)
|
||||
void DrawInitialInstance(gd::InitialInstance& instance,
|
||||
sf::RenderTarget& renderTarget,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout) override;
|
||||
bool GenerateThumbnail(const gd::Project& project,
|
||||
wxBitmap& thumbnail) const override;
|
||||
static void LoadEdittimeIcon();
|
||||
#endif
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties(
|
||||
gd::Project& project) const override;
|
||||
bool UpdateProperty(const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project) override;
|
||||
|
||||
private:
|
||||
void DoUnserializeFrom(gd::Project& project,
|
||||
const gd::SerializerElement& element) override;
|
||||
void DoSerializeTo(gd::SerializerElement& element) const override;
|
||||
|
||||
gd::String androidBannerId;
|
||||
gd::String androidInterstitialId;
|
||||
gd::String iosBannerId;
|
||||
gd::String iosInterstitialId;
|
||||
gd::String position; //"Top" or "Bottom"
|
||||
bool isTesting;
|
||||
bool overlap;
|
||||
bool showOnStartup;
|
||||
|
||||
#if !defined(GD_NO_WX_GUI)
|
||||
static sf::Texture edittimeIconImage;
|
||||
static sf::Sprite edittimeIcon;
|
||||
#endif
|
||||
};
|
||||
|
||||
gd::Object* CreateAdMobObject(gd::String name);
|
||||
|
||||
#endif // ADMOBOBJECT_H
|
@@ -1,21 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
cmake_policy(SET CMP0015 NEW)
|
||||
|
||||
project(AdMobObject)
|
||||
gd_add_extension_includes()
|
||||
|
||||
#Defines
|
||||
###
|
||||
gd_add_extension_definitions(AdMobObject)
|
||||
|
||||
#The targets
|
||||
###
|
||||
include_directories(.)
|
||||
file(GLOB source_files *.cpp *.h)
|
||||
gd_add_clang_utils(AdMobObject "${source_files}")
|
||||
|
||||
gd_add_extension_target(AdMobObject "${source_files}" "JsPlatform")
|
||||
|
||||
#Linker files for the IDE extension
|
||||
###
|
||||
gd_extension_link_libraries(AdMobObject)
|
@@ -1,94 +0,0 @@
|
||||
/**
|
||||
|
||||
GDevelop - AdMob Object Extension
|
||||
Copyright (c) 2008-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
#include "AdMobObject.h"
|
||||
|
||||
void DeclareAdMobObjectExtension(gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation(
|
||||
"AdMobObject",
|
||||
_("AdMob banners and interstitial screens"),
|
||||
_("Display an ads banner and interstitial screens powered by AdMob."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects/admob");
|
||||
|
||||
gd::ObjectMetadata& obj = extension.AddObject<AdMobObject>(
|
||||
"AdMob",
|
||||
_("AdMob banner"),
|
||||
_("Display an ad banner or interstitial screen using AdMob"),
|
||||
"JsPlatform/Extensions/admobicon.png");
|
||||
|
||||
obj.SetHelpUrl("/gdevelop/documentation/manual/built_admob");
|
||||
|
||||
#if !defined(GD_NO_WX_GUI)
|
||||
AdMobObject::LoadEdittimeIcon();
|
||||
#endif
|
||||
|
||||
obj.AddAction("ShowBanner",
|
||||
_("Show banner ad"),
|
||||
_("Show the banner ad"),
|
||||
_("Show the banner ad of _PARAM0_"),
|
||||
_("Banner"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png")
|
||||
.AddParameter("object", _("Object"), "AdMob");
|
||||
|
||||
obj.AddAction("HideBanner",
|
||||
_("Hide banner ad"),
|
||||
_("Hide the banner ad"),
|
||||
_("Hide the banner ad of _PARAM0_"),
|
||||
_("Banner"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png")
|
||||
.AddParameter("object", _("Object"), "AdMob");
|
||||
|
||||
obj.AddCondition(
|
||||
"BannerDisplayed",
|
||||
_("Banner is displayed"),
|
||||
_("Return true if the object is currently displaying a banner"),
|
||||
_("_PARAM0_ is displaying a banner"),
|
||||
"",
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png")
|
||||
.AddParameter("object", _("Object"), "AdMob");
|
||||
|
||||
obj.AddAction("PreloadInterstitial",
|
||||
_("Preload interstitial screen"),
|
||||
_("Preload the interstitial screen in memory, so that it can "
|
||||
"be shown later.\nYou can use this action at the beginning "
|
||||
"of a level for example."),
|
||||
_("Preload an interstitial screen for _PARAM0_"),
|
||||
_("Interstitial screen"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png")
|
||||
.AddParameter("object", _("Object"), "AdMob");
|
||||
|
||||
obj.AddAction(
|
||||
"ShowInterstitial",
|
||||
_("Show interstitial screen"),
|
||||
_("Show the interstitial screen.\nIf the interstitial screen has not "
|
||||
"been preloaded, it will be loaded and displayed when ready."),
|
||||
_("Show the interstitial screen of _PARAM0_"),
|
||||
_("Interstitial screen"),
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png")
|
||||
.AddParameter("object", _("Object"), "AdMob");
|
||||
|
||||
obj.AddCondition("InterstitialReady",
|
||||
_("Interstitial screen is ready"),
|
||||
_("Return true if the interstitial screen was loaded and is "
|
||||
"ready to be shown."),
|
||||
_("Interstitial screen of _PARAM0_ is ready"),
|
||||
"",
|
||||
"JsPlatform/Extensions/admobicon24.png",
|
||||
"JsPlatform/Extensions/admobicon16.png")
|
||||
.AddParameter("object", _("Object"), "AdMob");
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
|
||||
GDevelop - AdMob Object Extension
|
||||
Copyright (c) 2008-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
|
||||
#include "AdMobObject.h"
|
||||
|
||||
#include <iostream>
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
void DeclareAdMobObjectExtension(gd::PlatformExtension& extension);
|
||||
|
||||
/**
|
||||
* \brief This class declares information about the JS extension.
|
||||
*/
|
||||
class AdMobObjectJsExtension : public gd::PlatformExtension {
|
||||
public:
|
||||
/**
|
||||
* Constructor of an extension declares everything the extension contains:
|
||||
* objects, actions, conditions and expressions.
|
||||
*/
|
||||
AdMobObjectJsExtension() {
|
||||
DeclareAdMobObjectExtension(*this);
|
||||
|
||||
GetObjectMetadata("AdMobObject::AdMob")
|
||||
.SetIncludeFile("Extensions/AdMobObject/admobruntimeobject.js");
|
||||
|
||||
GetAllActionsForObject("AdMobObject::AdMob")["AdMobObject::ShowBanner"]
|
||||
.SetFunctionName("showBanner");
|
||||
GetAllActionsForObject("AdMobObject::AdMob")["AdMobObject::HideBanner"]
|
||||
.SetFunctionName("hideBanner");
|
||||
GetAllConditionsForObject(
|
||||
"AdMobObject::AdMob")["AdMobObject::BannerDisplayed"]
|
||||
.SetFunctionName("isBannerDisplayed");
|
||||
GetAllActionsForObject(
|
||||
"AdMobObject::AdMob")["AdMobObject::PreloadInterstitial"]
|
||||
.SetFunctionName("prepareInterstitial");
|
||||
GetAllActionsForObject(
|
||||
"AdMobObject::AdMob")["AdMobObject::ShowInterstitial"]
|
||||
.SetFunctionName("showInterstitial");
|
||||
GetAllConditionsForObject(
|
||||
"AdMobObject::AdMob")["AdMobObject::InterstitialReady"]
|
||||
.SetFunctionName("isInterstitialReady");
|
||||
|
||||
GD_COMPLETE_EXTENSION_COMPILATION_INFORMATION();
|
||||
};
|
||||
};
|
||||
|
||||
#if defined(EMSCRIPTEN)
|
||||
extern "C" gd::PlatformExtension* CreateGDJSAdMobObjectExtension() {
|
||||
return new AdMobObjectJsExtension;
|
||||
}
|
||||
#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 AdMobObjectJsExtension;
|
||||
}
|
||||
#endif
|
||||
#endif
|
@@ -1,160 +0,0 @@
|
||||
/**
|
||||
|
||||
GDevelop - AdMob Object Extension
|
||||
Copyright (c) 2008-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
if (typeof AdMob !== "undefined")
|
||||
console.warn("AdMob plugin for Cordova is not installed - no ads will be displayed. Ensure you have installed com.google.cordova.admob or cordova-plugin-admobpro.");
|
||||
|
||||
/**
|
||||
* The AdMobRuntimeObject displays an AdMob ad banner on screen.
|
||||
* This works with Cordova compatible platforms with `cordova-plugin-admobpro` plugin installed.
|
||||
*
|
||||
* @memberof gdjs
|
||||
* @class AdMobRuntimeObject
|
||||
* @extends RuntimeObject
|
||||
* @memberof gdjs
|
||||
*/
|
||||
gdjs.AdMobRuntimeObject = function(runtimeScene, objectData)
|
||||
{
|
||||
gdjs.RuntimeObject.call(this, runtimeScene, objectData);
|
||||
|
||||
this._androidBannerId = objectData.androidBannerId;
|
||||
this._androidInterstitialId = objectData.androidInterstitialId;
|
||||
this._iosBannerId = objectData.iosBannerId;
|
||||
this._iosInterstitialId = objectData.iosInterstitialId;
|
||||
this._isTesting = objectData.isTesting;
|
||||
this._position = objectData.position;
|
||||
this._overlap = objectData.overlap;
|
||||
this._showOnStartup = objectData.showOnStartup;
|
||||
|
||||
this._bannerDisplayed = false;
|
||||
this._interstitialReady = false;
|
||||
|
||||
if (this._showOnStartup)
|
||||
this.createBanner();
|
||||
|
||||
document.addEventListener('onAdPresent', this._onAdPresent.bind(this), false);
|
||||
document.addEventListener('onAdDismiss', this._onAdDismiss.bind(this), false);
|
||||
};
|
||||
|
||||
gdjs.AdMobRuntimeObject.prototype = Object.create( gdjs.RuntimeObject.prototype );
|
||||
gdjs.AdMobRuntimeObject.thisIsARuntimeObjectConstructor = "AdMobObject::AdMob";
|
||||
|
||||
gdjs.AdMobRuntimeObject.getPlatformName = function() {
|
||||
if( /(android)/i.test(navigator.userAgent) ) {
|
||||
return "android";
|
||||
} else if(/(ipod|iphone|ipad)/i.test(navigator.userAgent)) {
|
||||
return "ios";
|
||||
} else {
|
||||
return "windowsPhone";
|
||||
}
|
||||
};
|
||||
|
||||
gdjs.AdMobRuntimeObject.prototype._onAdPresent = function(data) {
|
||||
if (data.adType == 'interstitial')
|
||||
this._interstitialReady = false;
|
||||
};
|
||||
|
||||
gdjs.AdMobRuntimeObject.prototype._onAdDismiss = function(data) {
|
||||
if (data.adType == 'interstitial')
|
||||
this._interstitialReady = false;
|
||||
};
|
||||
|
||||
gdjs.AdMobRuntimeObject.prototype.createBanner = function() {
|
||||
if (typeof AdMob === "undefined") return;
|
||||
|
||||
var adName = "_" + gdjs.AdMobRuntimeObject.getPlatformName() + "BannerId";
|
||||
if (!this.hasOwnProperty(adName)) return;
|
||||
var adId = this[adName];
|
||||
|
||||
var position = AdMob.AD_POSITION.TOP_CENTER;
|
||||
if (this._position === "Bottom")
|
||||
position = AdMob.AD_POSITION.BOTTOM_CENTER;
|
||||
|
||||
var that = this;
|
||||
AdMob.createBanner({
|
||||
adId: adId || 'not-specified-xxx', //Avoid a crash by never letting the id empty.
|
||||
position: position,
|
||||
autoShow: true,
|
||||
overlap: this._overlap,
|
||||
isTesting: this._isTesting
|
||||
}, function() {
|
||||
that._bannerDisplayed = true;
|
||||
}, function() {
|
||||
that._bannerDisplayed = false;
|
||||
});
|
||||
};
|
||||
|
||||
gdjs.AdMobRuntimeObject.prototype.showBanner = function() {
|
||||
if (typeof AdMob === "undefined") return;
|
||||
|
||||
if (!this._bannerDisplayed)
|
||||
this.createBanner();
|
||||
}
|
||||
|
||||
gdjs.AdMobRuntimeObject.prototype.hideBanner = function() {
|
||||
if (typeof AdMob === "undefined") return;
|
||||
|
||||
this._bannerDisplayed = false;
|
||||
AdMob.removeBanner();
|
||||
};
|
||||
|
||||
gdjs.AdMobRuntimeObject.prototype.isBannerDisplayed = function() {
|
||||
return this._bannerDisplayed;
|
||||
};
|
||||
|
||||
gdjs.AdMobRuntimeObject.prototype.showInterstitial = function(runtimeScene) {
|
||||
if (typeof AdMob === "undefined") return;
|
||||
|
||||
if (!this._interstitialReady) {
|
||||
this.prepareInterstitial(function() {
|
||||
AdMob.showInterstitial();
|
||||
})
|
||||
} else {
|
||||
AdMob.showInterstitial();
|
||||
}
|
||||
};
|
||||
|
||||
gdjs.AdMobRuntimeObject.prototype.prepareInterstitial = function(cb) {
|
||||
if (typeof AdMob === "undefined") return;
|
||||
|
||||
var adName = "_" + gdjs.AdMobRuntimeObject.getPlatformName() + "InterstitialId";
|
||||
if (!this.hasOwnProperty(adName)) return;
|
||||
var adId = this[adName];
|
||||
|
||||
var that = this;
|
||||
AdMob.prepareInterstitial({
|
||||
adId: adId || 'not-specified-xxx', //Avoid a crash by never letting the id empty.
|
||||
autoShow: false
|
||||
}, function() {
|
||||
that._interstitialReady = true;
|
||||
cb();
|
||||
}, function() {
|
||||
that._interstitialReady = false;
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
gdjs.AdMobRuntimeObject.prototype.isInterstitialReady = function() {
|
||||
return this._interstitialReady;
|
||||
};
|
||||
|
||||
gdjs.AdMobRuntimeObject.prototype.onDeletedFromScene = function(runtimeScene) {
|
||||
gdjs.RuntimeObject.prototype.onDeletedFromScene.call(this, runtimeScene);
|
||||
if (typeof AdMob === "undefined") return;
|
||||
|
||||
document.removeEventListener('onAdPresent', this._onAdPresent, false);
|
||||
document.removeEventListener('onAdDismiss', this._onAdDismiss, false);
|
||||
if (this._bannerDisplayed) this.hideBanner();
|
||||
};
|
||||
|
||||
gdjs.AdMobRuntimeObject.prototype.setLayer = function(layer) {
|
||||
// No renderable object
|
||||
};
|
||||
|
||||
gdjs.AdMobRuntimeObject.prototype.setZOrder = function(z) {
|
||||
// No renderable object
|
||||
};
|
@@ -8,7 +8,6 @@ project(GD-Extensions)
|
||||
include(CMakeUtils.txt) #Functions to factor common tasks done in CMakeLists.txt of extensions
|
||||
|
||||
#Add all the CMakeLists:
|
||||
ADD_SUBDIRECTORY(AdMobObject)
|
||||
ADD_SUBDIRECTORY(AnchorBehavior)
|
||||
IF (NOT EMSCRIPTEN)
|
||||
ADD_SUBDIRECTORY(AdvancedXML)
|
||||
|
@@ -152,10 +152,6 @@ gdjs.PlatformRuntimeBehavior.prototype.doStepPreEvents = function(runtimeScene)
|
||||
gdjs.PlatformRuntimeBehavior.prototype.doStepPostEvents = function(runtimeScene) {
|
||||
};
|
||||
|
||||
gdjs.PlatformRuntimeBehavior.prototype.getAABB = function(){
|
||||
return this.owner.getAABB();
|
||||
};
|
||||
|
||||
gdjs.PlatformRuntimeBehavior.prototype.onActivate = function() {
|
||||
if (this._registeredInManager) return;
|
||||
|
||||
|
@@ -120,7 +120,7 @@ AdvancedExtension::AdvancedExtension() {
|
||||
parameterNameCode + ")) || 0 : 0)";
|
||||
});
|
||||
|
||||
GetAllExpressions()["GetArgumentAsString"]
|
||||
GetAllStrExpressions()["GetArgumentAsString"]
|
||||
.GetCodeExtraInformation()
|
||||
.SetCustomCodeGenerator([&generateParameterNameCode](
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
|
@@ -133,7 +133,6 @@ gd::PlatformExtension *CreateGDJSTiledSpriteObjectExtension();
|
||||
gd::PlatformExtension *CreateGDJSDraggableBehaviorExtension();
|
||||
gd::PlatformExtension *CreateGDJSTopDownMovementBehaviorExtension();
|
||||
gd::PlatformExtension *CreateGDJSTextObjectExtension();
|
||||
gd::PlatformExtension *CreateGDJSAdMobObjectExtension();
|
||||
gd::PlatformExtension *CreateGDJSPanelSpriteObjectExtension();
|
||||
gd::PlatformExtension *CreateGDJSAnchorBehaviorExtension();
|
||||
gd::PlatformExtension *CreateGDJSPrimitiveDrawingExtension();
|
||||
@@ -252,9 +251,6 @@ JsPlatform::JsPlatform() : gd::Platform() {
|
||||
AddExtension(std::shared_ptr<gd::PlatformExtension>(
|
||||
CreateGDJSPhysicsBehaviorExtension()));
|
||||
std::cout.flush();
|
||||
AddExtension(
|
||||
std::shared_ptr<gd::PlatformExtension>(CreateGDJSAdMobObjectExtension()));
|
||||
std::cout.flush();
|
||||
#endif
|
||||
std::cout << "done." << std::endl;
|
||||
};
|
||||
|
@@ -229,6 +229,13 @@ bool ExporterHelper::ExportCordovaConfigFile(const gd::Project &project,
|
||||
.FindAndReplace("GDJS_ICON_IOS_100",
|
||||
getIconFilename("ios", "icon-100"));
|
||||
|
||||
if(!project.GetAdMobAppId().empty()){
|
||||
str = str.FindAndReplace("<!-- GDJS_ADMOB_PLUGIN_AND_APPLICATION_ID -->",
|
||||
"<plugin name=\"cordova-plugin-admob-free\" spec=\"~0.21.0\">\n"
|
||||
"\t\t<variable name=\"ADMOB_APP_ID\" value=\"" + project.GetAdMobAppId() + "\" />\n"
|
||||
"\t</plugin>");
|
||||
}
|
||||
|
||||
if (!fs.WriteToFile(exportDir + "/config.xml", str)) {
|
||||
lastError = "Unable to write configuration file.";
|
||||
return false;
|
||||
|
@@ -55,4 +55,6 @@
|
||||
</platform>
|
||||
<preference name="orientation" value="GDJS_ORIENTATION" />
|
||||
<preference name="BackgroundColor" value="0xff000000"/>
|
||||
<preference name="phonegap-version" value="cli-8.0.0" />
|
||||
<!-- GDJS_ADMOB_PLUGIN_AND_APPLICATION_ID -->
|
||||
</widget>
|
||||
|
@@ -112,10 +112,12 @@ gdjs.LayerCocosRenderer.prototype.updatePosition = function() {
|
||||
this._cocosLayer.setRotation(-this._layer.getCameraRotation());
|
||||
this._cocosLayer.setScale(zoomFactor, zoomFactor);
|
||||
|
||||
var centerX = (this._layer.getCameraX()-this._layer.getWidth()/2)*Math.cos(-angle)
|
||||
- (this._layer.getCameraY()-this._layer.getHeight()/2)*Math.sin(-angle);
|
||||
var centerY = (this._layer.getCameraX()-this._layer.getWidth()/2)*Math.sin(-angle)
|
||||
+ (this._layer.getCameraY()-this._layer.getHeight()/2)*Math.cos(-angle);
|
||||
var cosValue = Math.cos(-angle);
|
||||
var sinValue = Math.sin(-angle);
|
||||
var centerX = (this._layer.getCameraX()-this._layer.getWidth()/2)*cosValue
|
||||
- (this._layer.getCameraY()-this._layer.getHeight()/2)*sinValue;
|
||||
var centerY = (this._layer.getCameraX()-this._layer.getWidth()/2)*sinValue
|
||||
+ (this._layer.getCameraY()-this._layer.getHeight()/2)*cosValue;
|
||||
|
||||
this._cocosLayer.setPositionX(-centerX);
|
||||
this._cocosLayer.setPositionY(+centerY);
|
||||
|
@@ -168,6 +168,10 @@ gdjs.RuntimeSceneCocosRenderer.prototype.makeEventListeners = function() {
|
||||
})];
|
||||
}
|
||||
|
||||
gdjs.RuntimeSceneCocosRenderer.prototype.renderDebugDraw = function() {
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
gdjs.RuntimeSceneCocosRenderer.prototype.hideCursor = function() {
|
||||
//TODO
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ gdjs.Force = function(x,y, clearing)
|
||||
{
|
||||
this._x = x || 0;
|
||||
this._y = y || 0;
|
||||
this._angle = Math.atan2(y,x)*180/3.14159;
|
||||
this._angle = Math.atan2(y,x)*180/Math.PI;
|
||||
this._length = Math.sqrt(x*x+y*y);
|
||||
this._dirty = false;
|
||||
this._clearing = clearing;
|
||||
@@ -67,8 +67,9 @@ gdjs.Force.prototype.setAngle = function(angle) {
|
||||
}
|
||||
|
||||
this._angle = angle;
|
||||
this._x = Math.cos(angle/180*3.14159)*this._length;
|
||||
this._y = Math.sin(angle/180*3.14159)*this._length;
|
||||
var angleInRadians = angle/180*Math.PI;
|
||||
this._x = Math.cos(angleInRadians)*this._length;
|
||||
this._y = Math.sin(angleInRadians)*this._length;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,13 +79,14 @@ gdjs.Force.prototype.setAngle = function(angle) {
|
||||
gdjs.Force.prototype.setLength = function(len) {
|
||||
|
||||
if ( this._dirty ) {
|
||||
this._angle = Math.atan2(this._y, this._x)*180/3.14159;
|
||||
this._angle = Math.atan2(this._y, this._x)*180/Math.PI;
|
||||
this._dirty = false;
|
||||
}
|
||||
|
||||
this._length = len;
|
||||
this._x = Math.cos(this._angle/180*3.14159)*this._length;
|
||||
this._y = Math.sin(this._angle/180*3.14159)*this._length;
|
||||
var angleInRadians = this._angle/180*Math.PI;
|
||||
this._x = Math.cos(angleInRadians)*this._length;
|
||||
this._y = Math.sin(angleInRadians)*this._length;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +94,7 @@ gdjs.Force.prototype.setLength = function(len) {
|
||||
*/
|
||||
gdjs.Force.prototype.getAngle = function() {
|
||||
if ( this._dirty ) {
|
||||
this._angle = Math.atan2(this._y, this._x)*180/3.14159;
|
||||
this._angle = Math.atan2(this._y, this._x)*180/Math.PI;
|
||||
this._length = Math.sqrt(this._x*this._x+this._y*this._y);
|
||||
|
||||
this._dirty = false;
|
||||
@@ -107,7 +109,7 @@ gdjs.Force.prototype.getAngle = function() {
|
||||
*/
|
||||
gdjs.Force.prototype.getLength = function() {
|
||||
if ( this._dirty ) {
|
||||
this._angle = Math.atan2(this._y, this._x)*180/3.14159;
|
||||
this._angle = Math.atan2(this._y, this._x)*180/Math.PI;
|
||||
this._length = Math.sqrt(this._x*this._x+this._y*this._y);
|
||||
|
||||
this._dirty = false;
|
||||
|
@@ -171,23 +171,31 @@ gdjs.Layer.prototype.convertCoords = function(x, y, cameraId) {
|
||||
x /= Math.abs(this._zoomFactor);
|
||||
y /= Math.abs(this._zoomFactor);
|
||||
|
||||
// Only compute angle and cos/sin once (allow heavy optimization from JS engines).
|
||||
var angleInRadians = this._cameraRotation/180*Math.PI;
|
||||
var tmp = x;
|
||||
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;
|
||||
var cosValue = Math.cos(angleInRadians);
|
||||
var sinValue = Math.sin(angleInRadians);
|
||||
x = cosValue*x - sinValue*y;
|
||||
y = sinValue*tmp + cosValue*y;
|
||||
|
||||
return [x + this.getCameraX(cameraId), y + this.getCameraY(cameraId)];
|
||||
};
|
||||
|
||||
gdjs.Layer.prototype.convertInverseCoords = function(x, y, cameraId) {
|
||||
x -= this.getCameraX(cameraId);
|
||||
y -= this.getCameraY(cameraId);
|
||||
x -= this.getCameraX(cameraId);
|
||||
y -= this.getCameraY(cameraId);
|
||||
|
||||
// Only compute angle and cos/sin once (allow heavy optimization from JS engines).
|
||||
var angleInRadians = this._cameraRotation/180*Math.PI;
|
||||
var tmp = x;
|
||||
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;
|
||||
var cosValue = Math.cos(-angleInRadians);
|
||||
var sinValue = Math.sin(-angleInRadians);
|
||||
x = cosValue*x - sinValue*y;
|
||||
y = sinValue*tmp + cosValue*y;
|
||||
|
||||
x *= Math.abs(this._zoomFactor);
|
||||
y *= Math.abs(this._zoomFactor);
|
||||
x *= Math.abs(this._zoomFactor);
|
||||
y *= Math.abs(this._zoomFactor);
|
||||
|
||||
return [x + this._width/2, y + this._height/2];
|
||||
};
|
||||
|
@@ -23,10 +23,12 @@ gdjs.LayerPixiRenderer.prototype.updatePosition = function() {
|
||||
this._pixiContainer.scale.x = zoomFactor;
|
||||
this._pixiContainer.scale.y = zoomFactor;
|
||||
|
||||
var centerX = (this._layer.getCameraX()*zoomFactor)*Math.cos(angle)
|
||||
- (this._layer.getCameraY()*zoomFactor)*Math.sin(angle);
|
||||
var centerY = (this._layer.getCameraX()*zoomFactor)*Math.sin(angle)
|
||||
+ (this._layer.getCameraY()*zoomFactor)*Math.cos(angle);
|
||||
var cosValue = Math.cos(angle);
|
||||
var sinValue = Math.sin(angle);
|
||||
var centerX = (this._layer.getCameraX()*zoomFactor)*cosValue
|
||||
- (this._layer.getCameraY()*zoomFactor)*sinValue;
|
||||
var centerY = (this._layer.getCameraX()*zoomFactor)*sinValue
|
||||
+ (this._layer.getCameraY()*zoomFactor)*cosValue;
|
||||
|
||||
this._pixiContainer.position.x = -centerX;
|
||||
this._pixiContainer.position.y = -centerY;
|
||||
|
@@ -47,6 +47,33 @@ gdjs.RuntimeScenePixiRenderer.prototype._renderProfileText = function() {
|
||||
this._profilerText.text = outputs.join("\n");
|
||||
};
|
||||
|
||||
gdjs.RuntimeScenePixiRenderer.prototype.renderDebugDraw = function(instances, layersCameraCoordinates) {
|
||||
if (!this._debugDraw) {
|
||||
this._debugDraw = new PIXI.Graphics();
|
||||
this._pixiContainer.addChild(this._debugDraw);
|
||||
}
|
||||
/** @type PIXI.Graphics */
|
||||
var debugDraw = this._debugDraw;
|
||||
|
||||
debugDraw.clear();
|
||||
debugDraw.beginFill(0x6868e8);
|
||||
debugDraw.lineStyle(1, 0x6868e8, 1);
|
||||
debugDraw.fillAlpha = 0.1;
|
||||
debugDraw.alpha = 0.8;
|
||||
|
||||
for(var i = 0;i < instances.length;i++) {
|
||||
var object = instances[i];
|
||||
var cameraCoords = layersCameraCoordinates[object.getLayer()];
|
||||
var rendererObject = object.getRendererObject();
|
||||
|
||||
if (!cameraCoords || !rendererObject) continue;
|
||||
|
||||
var aabb = object.getAABB();
|
||||
debugDraw.drawRect(aabb.min[0], aabb.min[1], aabb.max[0] - aabb.min[0], aabb.max[1] - aabb.min[1]);
|
||||
}
|
||||
debugDraw.endFill();
|
||||
};
|
||||
|
||||
gdjs.RuntimeScenePixiRenderer.prototype.hideCursor = function() {
|
||||
this._pixiRenderer.view.style.cursor = "none";
|
||||
};
|
||||
|
@@ -601,8 +601,9 @@ gdjs.RuntimeObject.prototype.addForce = function(x,y, clearing) {
|
||||
* @param {number} clearing Set the force clearing
|
||||
*/
|
||||
gdjs.RuntimeObject.prototype.addPolarForce = function(angle, len, clearing) {
|
||||
var forceX = Math.cos(angle/180*3.14159)*len;
|
||||
var forceY = Math.sin(angle/180*3.14159)*len;
|
||||
var angleInRadians = angle/180*3.14159; //TODO: Benchmark with Math.PI
|
||||
var forceX = Math.cos(angleInRadians)*len;
|
||||
var forceY = Math.sin(angleInRadians)*len;
|
||||
|
||||
this._forces.push(this._getRecycledForce(forceX, forceY, clearing));
|
||||
};
|
||||
@@ -713,8 +714,10 @@ gdjs.RuntimeObject.prototype.averageForceAngleIs = function(angle, toleranceInDe
|
||||
|
||||
/**
|
||||
* Get the hit boxes for the object.<br>
|
||||
* The default implementation returns a basic bouding box based on the result of getWidth and
|
||||
* getHeight. You should probably redefine updateHitBoxes instead of this function.
|
||||
* The default implementation returns a basic bouding box based the size (getWidth and
|
||||
* getHeight) and the center point of the object (getCenterX and getCenterY).
|
||||
*
|
||||
* You should probably redefine updateHitBoxes instead of this function.
|
||||
*
|
||||
* @return {Array} An array composed of polygon.
|
||||
*/
|
||||
@@ -732,35 +735,61 @@ gdjs.RuntimeObject.prototype.getHitBoxes = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the hit boxes for the object.<br>
|
||||
* The default implementation set a basic bouding box based on the result of getWidth and
|
||||
* getHeight.
|
||||
* Update the hit boxes for the object.
|
||||
*
|
||||
* The default implementation set a basic bounding box based on the size (getWidth and
|
||||
* getHeight) and the center point of the object (getCenterX and getCenterY).
|
||||
* Result is cached until invalidated (by a position change, angle change...).
|
||||
*
|
||||
* You should not call this function by yourself, it is called when necessary by getHitBoxes method.
|
||||
* However, you can redefine it if your object need custom hit boxes.
|
||||
*
|
||||
*/
|
||||
gdjs.RuntimeObject.prototype.updateHitBoxes = function() {
|
||||
|
||||
//Ensure we're using the default hitbox (a single rectangle)
|
||||
this.hitBoxes = this._defaultHitBoxes;
|
||||
|
||||
var width = this.getWidth();
|
||||
var height = this.getHeight();
|
||||
this.hitBoxes[0].vertices[0][0] =-width/2.0;
|
||||
this.hitBoxes[0].vertices[0][1] =-height/2.0;
|
||||
this.hitBoxes[0].vertices[1][0] =+width/2.0;
|
||||
this.hitBoxes[0].vertices[1][1] =-height/2.0;
|
||||
this.hitBoxes[0].vertices[2][0] =+width/2.0;
|
||||
this.hitBoxes[0].vertices[2][1] =+height/2.0;
|
||||
this.hitBoxes[0].vertices[3][0] =-width/2.0;
|
||||
this.hitBoxes[0].vertices[3][1] =+height/2.0;
|
||||
var centerX = this.getCenterX();
|
||||
var centerY = this.getCenterY();
|
||||
|
||||
this.hitBoxes[0].rotate(this.getAngle()/180*3.14159);
|
||||
this.hitBoxes[0].move(this.getDrawableX()+this.getCenterX(), this.getDrawableY()+this.getCenterY());
|
||||
if (this.getCenterX() === width / 2 && this.getCenterY() === height / 2) {
|
||||
this.hitBoxes[0].vertices[0][0] =-width/2.0;
|
||||
this.hitBoxes[0].vertices[0][1] =-height/2.0;
|
||||
this.hitBoxes[0].vertices[1][0] =+width/2.0;
|
||||
this.hitBoxes[0].vertices[1][1] =-height/2.0;
|
||||
this.hitBoxes[0].vertices[2][0] =+width/2.0;
|
||||
this.hitBoxes[0].vertices[2][1] =+height/2.0;
|
||||
this.hitBoxes[0].vertices[3][0] =-width/2.0;
|
||||
this.hitBoxes[0].vertices[3][1] =+height/2.0;
|
||||
-
|
||||
this.hitBoxes[0].rotate(this.getAngle()/180*Math.PI);
|
||||
this.hitBoxes[0].move(this.getDrawableX()+this.getCenterX(), this.getDrawableY()+this.getCenterY());
|
||||
} else {
|
||||
this.hitBoxes[0].vertices[0][0] = 0;
|
||||
this.hitBoxes[0].vertices[0][1] = 0;
|
||||
this.hitBoxes[0].vertices[1][0] = width;
|
||||
this.hitBoxes[0].vertices[1][1] = 0;
|
||||
this.hitBoxes[0].vertices[2][0] = width;
|
||||
this.hitBoxes[0].vertices[2][1] = height;
|
||||
this.hitBoxes[0].vertices[3][0] = 0;
|
||||
this.hitBoxes[0].vertices[3][1] = height;
|
||||
|
||||
this.hitBoxes[0].move(-centerX, -centerY);
|
||||
this.hitBoxes[0].rotate(this.getAngle()/180*Math.PI);
|
||||
this.hitBoxes[0].move(this.getDrawableX()+centerX, this.getDrawableY()+centerY);
|
||||
}
|
||||
};
|
||||
|
||||
//Experimental
|
||||
/**
|
||||
* Get the AABB (axis aligned bounding box) for the object.
|
||||
*
|
||||
* The default implementation uses either the position/size of the object (when angle is 0) or
|
||||
* hitboxes (when angle is not 0) to compute the bounding box.
|
||||
* Result is cached until invalidated (by a position change, angle change...).
|
||||
*
|
||||
* You should probably redefine updateAABB instead of this function.
|
||||
*
|
||||
* @return The bounding box (example: {min: [10,5], max:[20,10]})
|
||||
*/
|
||||
gdjs.RuntimeObject.prototype.getAABB = function() {
|
||||
if ( this.hitBoxesDirty ) {
|
||||
this.updateHitBoxes();
|
||||
@@ -771,11 +800,48 @@ gdjs.RuntimeObject.prototype.getAABB = function() {
|
||||
return this.aabb;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the AABB (axis aligned bounding box) for the object.
|
||||
*
|
||||
* Default implementation uses either the position/size of the object (when angle is 0) or
|
||||
* hitboxes (when angle is not 0) to compute the bounding box.
|
||||
*
|
||||
* You should not call this function by yourself, it is called when necessary by getAABB method.
|
||||
* However, you can redefine it if your object can have a faster implementation.
|
||||
*/
|
||||
gdjs.RuntimeObject.prototype.updateAABB = function() {
|
||||
this.aabb.min[0] = this.getDrawableX();
|
||||
this.aabb.min[1] = this.getDrawableY();
|
||||
this.aabb.max[0] = this.aabb.min[0] + this.getWidth();
|
||||
this.aabb.max[1] = this.aabb.min[1] + this.getHeight();
|
||||
if (this.getAngle() === 0) {
|
||||
// Fast/simple computation of AABB for non rotated object
|
||||
// (works even for object with non default center/origin
|
||||
// because we're using getDrawableX/Y)
|
||||
this.aabb.min[0] = this.getDrawableX();
|
||||
this.aabb.min[1] = this.getDrawableY();
|
||||
this.aabb.max[0] = this.aabb.min[0] + this.getWidth();
|
||||
this.aabb.max[1] = this.aabb.min[1] + this.getHeight();
|
||||
} else {
|
||||
// Use hitboxes if object is rotated to ensure that the AABB
|
||||
// is properly bounding the whole object.
|
||||
// Slower (10-15% slower).
|
||||
var first = true;
|
||||
for(var i = 0;i<this.hitBoxes.length;i++) {
|
||||
for(var j = 0;j<this.hitBoxes[i].vertices.length;j++) {
|
||||
var vertex = this.hitBoxes[i].vertices[j];
|
||||
|
||||
if (first) {
|
||||
this.aabb.min[0] = vertex[0];
|
||||
this.aabb.max[0] = vertex[0];
|
||||
this.aabb.min[1] = vertex[1];
|
||||
this.aabb.max[1] = vertex[1];
|
||||
first = false;
|
||||
} else {
|
||||
this.aabb.min[0] = Math.min(this.aabb.min[0], vertex[0]);
|
||||
this.aabb.max[0] = Math.max(this.aabb.max[0], vertex[0]);
|
||||
this.aabb.min[1] = Math.min(this.aabb.min[1], vertex[1]);
|
||||
this.aabb.max[1] = Math.max(this.aabb.max[1], vertex[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//Behaviors:
|
||||
|
@@ -240,7 +240,14 @@ gdjs.RuntimeScene.prototype.renderAndStep = function(elapsedTime) {
|
||||
this._updateObjectsVisibility();
|
||||
if (this._profiler) this._profiler.end("objects (visibility)");
|
||||
|
||||
if (this._profiler) this._profiler.begin("render");
|
||||
if (this._profiler) this._profiler.begin("render");
|
||||
|
||||
// Uncomment to enable debug rendering (look for the implementation in the renderer
|
||||
// to see what is rendered)
|
||||
// if (this._layersCameraCoordinates) {
|
||||
// this.getRenderer().renderDebugDraw(this._allInstancesList, this._layersCameraCoordinates); //TODO
|
||||
// }
|
||||
|
||||
this.render();
|
||||
if (this._profiler) this._profiler.end("render");
|
||||
|
||||
|
@@ -554,8 +554,13 @@ gdjs.SpriteRuntimeObject.prototype._transformToGlobal = function(x, y, result) {
|
||||
|
||||
//Rotation
|
||||
var oldX = x;
|
||||
x = cx + Math.cos(this.angle/180*3.14159)*(x-cx) - Math.sin(this.angle/180*3.14159)*(y-cy);
|
||||
y = cy + Math.sin(this.angle/180*3.14159)*(oldX-cx) + Math.cos(this.angle/180*3.14159)*(y-cy);
|
||||
var angleInRadians = this.angle/180*Math.PI;
|
||||
var cosValue = Math.cos(angleInRadians); // Only compute cos and sin once (10% faster than doing it twice)
|
||||
var sinValue = Math.sin(angleInRadians);
|
||||
var xToCenterXDelta = x-cx;
|
||||
var yToCenterYDelta = y-cy;
|
||||
x = cx + cosValue*(xToCenterXDelta) - sinValue*(yToCenterYDelta);
|
||||
y = cy + sinValue*(xToCenterXDelta) + cosValue*(yToCenterYDelta);
|
||||
|
||||
result.length = 2;
|
||||
result[0] = x + this.getDrawableX();
|
||||
|
14
GDJS/tests/benchmarks/force.js
Normal file
@@ -0,0 +1,14 @@
|
||||
describe('gdjs.Force', function() {
|
||||
it('benchmark setting angle and length', function(){
|
||||
this.timeout(6000);
|
||||
var layer = new gdjs.Force();
|
||||
|
||||
const benchmarkSuite = makeBenchmarkSuite();
|
||||
benchmarkSuite.add('setAngle and setLength', (i) => {
|
||||
layer.setAngle(i);
|
||||
layer.setLength(200);
|
||||
});
|
||||
|
||||
console.log(benchmarkSuite.run());
|
||||
});
|
||||
});
|
47
GDJS/tests/benchmarks/init.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Helper allowing to run a benchmark of the time spent the execute a certain
|
||||
* number of iterations of one or more functions.
|
||||
*
|
||||
* Note that this could surely be replaced by a more robust solution like
|
||||
* Benchmark.js
|
||||
*
|
||||
* @param {*} options
|
||||
*/
|
||||
let makeBenchmarkSuite = (options = {}) => {
|
||||
const benchmarkTimings = {};
|
||||
const benchmarksCount = options.benchmarksCount || 1000;
|
||||
const iterationsCount = options.iterationsCount || 100000;
|
||||
const testCases = [];
|
||||
|
||||
const suite = {};
|
||||
suite.add = (title, fn) => {
|
||||
testCases.push({ title, fn });
|
||||
return suite;
|
||||
};
|
||||
suite.run = () => {
|
||||
for (
|
||||
let benchmarkIndex = 0;
|
||||
benchmarkIndex < benchmarksCount;
|
||||
benchmarkIndex++
|
||||
) {
|
||||
testCases.forEach(testCase => {
|
||||
const description = testCase.title + '(' + iterationsCount + 'x)';
|
||||
const start = performance.now();
|
||||
for (let i = 0; i < iterationsCount; i++) {
|
||||
testCase.fn(i);
|
||||
}
|
||||
benchmarkTimings[description] = benchmarkTimings[description] || [];
|
||||
benchmarkTimings[description].push(performance.now() - start);
|
||||
});
|
||||
}
|
||||
|
||||
const results = {};
|
||||
for (let benchmarkName in benchmarkTimings) {
|
||||
results[benchmarkName] =
|
||||
benchmarkTimings[benchmarkName].reduce((sum, value) => sum + value, 0) /
|
||||
benchmarksCount;
|
||||
}
|
||||
return results;
|
||||
};
|
||||
return suite;
|
||||
};
|
29
GDJS/tests/benchmarks/layer.js
Normal file
@@ -0,0 +1,29 @@
|
||||
describe('gdjs.Layer', function() {
|
||||
var runtimeGame = new gdjs.RuntimeGame({
|
||||
variables: [],
|
||||
properties: { windowWidth: 800, windowHeight: 600 },
|
||||
});
|
||||
var runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
|
||||
it('benchmark convertCoords and convertInverseCoords', function() {
|
||||
this.timeout(6000);
|
||||
var layer = new gdjs.Layer(
|
||||
{ name: 'My layer', visibility: true, effects: [] },
|
||||
runtimeScene
|
||||
);
|
||||
layer.setCameraX(100, 0);
|
||||
layer.setCameraY(200, 0);
|
||||
layer.setCameraRotation(90, 0);
|
||||
|
||||
const benchmarkSuite = makeBenchmarkSuite();
|
||||
benchmarkSuite
|
||||
.add('convertCoords', () => {
|
||||
layer.convertCoords(350, 450, 0);
|
||||
})
|
||||
.add('convertInverseCoords', () => {
|
||||
layer.convertInverseCoords(350, 450, 0);
|
||||
});
|
||||
|
||||
console.log(benchmarkSuite.run());
|
||||
});
|
||||
});
|
53
GDJS/tests/benchmarks/runtimeobject.js
Normal file
@@ -0,0 +1,53 @@
|
||||
describe('gdjs.RuntimeObject', function() {
|
||||
const runtimeScene = new gdjs.RuntimeScene(null);
|
||||
|
||||
it('benchmark getAABB of rotated vs non rotated objects', function(){
|
||||
var object = new gdjs.RuntimeObject(runtimeScene, {name: "obj1", type: "", behaviors: []});
|
||||
object.getWidth = function() { return 10; };
|
||||
object.getHeight = function() { return 20; };
|
||||
object.setPosition(15, 20);
|
||||
|
||||
const benchmarkSuite = makeBenchmarkSuite({
|
||||
benchmarksCount: 60,
|
||||
iterationsCount: 60000,
|
||||
});
|
||||
benchmarkSuite
|
||||
.add('getAABB of a non rotated, default center', (i) => {
|
||||
object.setX(i);
|
||||
object.getAABB();
|
||||
})
|
||||
.add('getAABB of a rotated, default center', (i) => {
|
||||
object.setX(i);
|
||||
object.getAABB();
|
||||
});
|
||||
|
||||
console.log(benchmarkSuite.run());
|
||||
});
|
||||
|
||||
it('benchmark getAABB of rotated vs non rotated objects, with non default center', function(){
|
||||
var object = new gdjs.RuntimeObject(runtimeScene, {name: "obj1", type: "", behaviors: []});
|
||||
object.getWidth = function() { return 10; };
|
||||
object.getHeight = function() { return 20; };
|
||||
object.getCenterX = function() { return 0 };
|
||||
object.getCenterY = function() { return 0 };
|
||||
object.setPosition(15, 20);
|
||||
|
||||
const benchmarkSuite = makeBenchmarkSuite({
|
||||
benchmarksCount: 60,
|
||||
iterationsCount: 60000,
|
||||
});
|
||||
benchmarkSuite
|
||||
.add('getAABB of a non rotated, non default center', (i) => {
|
||||
object.setAngle(0);
|
||||
object.setX(i);
|
||||
object.getAABB();
|
||||
})
|
||||
.add('getAABB of a rotated, non default center', (i) => {
|
||||
object.setAngle(90);
|
||||
object.setX(i);
|
||||
object.getAABB();
|
||||
});
|
||||
|
||||
console.log(benchmarkSuite.run());
|
||||
});
|
||||
});
|
86
GDJS/tests/benchmarks/spriteruntimeobject.js
Normal file
@@ -0,0 +1,86 @@
|
||||
describe('gdjs.SpriteRuntimeObject', function() {
|
||||
var runtimeGame = new gdjs.RuntimeGame({variables: [], properties: {windowWidth: 800, windowHeight: 600}});
|
||||
var runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
|
||||
const makeSpriteRuntimeObjectWithCustomHitBox = (runtimeScene) => new gdjs.SpriteRuntimeObject(runtimeScene, {
|
||||
"name": "obj1",
|
||||
"type": "Sprite",
|
||||
"updateIfNotVisible": false,
|
||||
"variables": [],
|
||||
"behaviors": [],
|
||||
"animations": [
|
||||
{
|
||||
"name": "NewObject2",
|
||||
"useMultipleDirections": false,
|
||||
"directions": [
|
||||
{
|
||||
"looping": false,
|
||||
"timeBetweenFrames": 1,
|
||||
"sprites": [
|
||||
{
|
||||
"hasCustomCollisionMask": true,
|
||||
"image": "NewObject2-2.png",
|
||||
"points": [],
|
||||
"originPoint": {
|
||||
"name": "origine",
|
||||
"x": 32,
|
||||
"y": 16
|
||||
},
|
||||
"centerPoint": {
|
||||
"automatic": false,
|
||||
"name": "centre",
|
||||
"x": 64,
|
||||
"y": 31
|
||||
},
|
||||
"customCollisionMask": [
|
||||
[
|
||||
{
|
||||
"x": 12.5,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 41.5,
|
||||
"y": 2
|
||||
},
|
||||
{
|
||||
"x": 55.5,
|
||||
"y": 31
|
||||
},
|
||||
{
|
||||
"x": 24.5,
|
||||
"y": 30
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
it('benchmark getAABB of rotated vs non rotated sprite, with custom hitboxes, origin and center', function(){
|
||||
this.timeout(6000);
|
||||
const object = makeSpriteRuntimeObjectWithCustomHitBox(runtimeScene);
|
||||
|
||||
const benchmarkSuite = makeBenchmarkSuite({
|
||||
benchmarksCount: 60,
|
||||
iterationsCount: 60000,
|
||||
});
|
||||
benchmarkSuite
|
||||
.add('getAABB of a non rotated sprite, with custom hitboxes, origin and center', (i) => {
|
||||
object.setAngle(0);
|
||||
object.setX(i);
|
||||
object.getAABB();
|
||||
})
|
||||
.add('getAABB of a rotated sprite, with custom hitboxes, origin and center', (i) => {
|
||||
object.setAngle(90);
|
||||
object.setX(i);
|
||||
object.getAABB();
|
||||
});
|
||||
|
||||
console.log(benchmarkSuite.run());
|
||||
});
|
||||
});
|
@@ -111,6 +111,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "p1_stand.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "p1_stand.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -119,6 +120,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "p1_jump.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "p1_jump.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -127,6 +129,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "p1_walk01.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "p1_walk01.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -135,6 +138,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "p1_walk02.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "p1_walk02.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -143,6 +147,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "p1_walk03.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "p1_walk03.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -151,6 +156,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "p1_walk04.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "p1_walk04.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -159,6 +165,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "p1_walk05.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "p1_walk05.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -167,6 +174,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "p1_walk06.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "p1_walk06.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -175,6 +183,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "p1_walk07.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "p1_walk07.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -183,6 +192,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "p1_walk08.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "p1_walk08.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -191,6 +201,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "p1_walk09.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "p1_walk09.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -199,6 +210,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "p1_walk10.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "p1_walk10.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -207,6 +219,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "p1_walk11.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "p1_walk11.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -215,6 +228,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "brickWall.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "brickWall.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -223,6 +237,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "bridge.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "bridge.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -231,6 +246,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "grassHalfMid.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "grassHalfMid.png",
|
||||
"smoothed": true,
|
||||
"userAdded": true
|
||||
@@ -239,6 +255,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "castleCenter.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "castleCenter.png",
|
||||
"smoothed": true,
|
||||
"userAdded": true
|
||||
@@ -247,6 +264,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "bridgeLogs.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "bridgeLogs.png",
|
||||
"smoothed": true,
|
||||
"userAdded": true
|
||||
@@ -255,6 +273,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "Left.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "Left.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -263,6 +282,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "Right.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "Right.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -271,6 +291,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "ladder_mid.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "ladder_mid.png",
|
||||
"smoothed": true,
|
||||
"userAdded": true
|
||||
@@ -279,6 +300,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "Grass.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "grass.png",
|
||||
"smoothed": true,
|
||||
"userAdded": true
|
||||
@@ -287,6 +309,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "PlayerArea.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "PlayerArea.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -295,6 +318,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "slimeWalk1.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "slimeWalk1.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -303,6 +327,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "slimeWalk2.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "slimeWalk2.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -311,6 +336,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "slimeDead.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "slimeDead.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -319,6 +345,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "flyFly1.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "flyFly1.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -327,6 +354,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "flyFly2.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "flyFly2.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -335,6 +363,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "flyDead.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "flyDead.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -343,6 +372,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "cloud1.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "cloud1.png",
|
||||
"smoothed": false,
|
||||
"userAdded": false
|
||||
@@ -351,6 +381,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "cloud2.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "cloud2.png",
|
||||
"smoothed": false,
|
||||
"userAdded": false
|
||||
@@ -359,6 +390,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "cloud3.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "cloud3.png",
|
||||
"smoothed": false,
|
||||
"userAdded": false
|
||||
@@ -367,6 +399,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "bush.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "bush.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -375,6 +408,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "cactus.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "cactus.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -383,6 +417,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "plant.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "plant.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -391,6 +426,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "coinGold.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "coinGold.png",
|
||||
"smoothed": true,
|
||||
"userAdded": true
|
||||
@@ -399,6 +435,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "shadedDark06.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "shadedDark06.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -407,6 +444,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "shadedDark05.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "shadedDark05.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -415,6 +453,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "shadedDark45.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "shadedDark45.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -423,6 +462,7 @@
|
||||
"alwaysLoaded": false,
|
||||
"file": "shadedDark09.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "shadedDark09.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
@@ -3631,7 +3671,7 @@
|
||||
"textG": 0,
|
||||
"textR": 0
|
||||
},
|
||||
"comment": "Platform should rotate =====>",
|
||||
"comment": "Platform should rotate, platforms should be colored",
|
||||
"comment2": ""
|
||||
},
|
||||
{
|
||||
@@ -3684,7 +3724,9 @@
|
||||
},
|
||||
"parameters": [
|
||||
"",
|
||||
"Platform"
|
||||
"Platform",
|
||||
"\"0;255;100\"",
|
||||
""
|
||||
],
|
||||
"subInstructions": []
|
||||
}
|
||||
@@ -5227,8 +5269,8 @@
|
||||
"version": "",
|
||||
"eventsFunctions": [
|
||||
{
|
||||
"description": "t",
|
||||
"fullName": "t",
|
||||
"description": "Rotate the given object",
|
||||
"fullName": "Rotate function",
|
||||
"functionType": "Action",
|
||||
"name": "RotatePlease",
|
||||
"sentence": "Rotate the _PARAM1_ at speed _PARAM2_deg/sec",
|
||||
@@ -5256,15 +5298,6 @@
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"codeOnly": true,
|
||||
"defaultValue": "",
|
||||
"description": "",
|
||||
"name": "runtimeScene",
|
||||
"optional": false,
|
||||
"supplementaryInformation": "",
|
||||
"type": "currentScene"
|
||||
},
|
||||
{
|
||||
"codeOnly": false,
|
||||
"defaultValue": "",
|
||||
@@ -5312,17 +5345,7 @@
|
||||
"events": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"codeOnly": true,
|
||||
"defaultValue": "",
|
||||
"description": "",
|
||||
"name": "runtimeScene",
|
||||
"optional": false,
|
||||
"supplementaryInformation": "",
|
||||
"type": "currentScene"
|
||||
}
|
||||
]
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"description": "Return a speed of rotation",
|
||||
@@ -5351,24 +5374,14 @@
|
||||
"events": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"codeOnly": true,
|
||||
"defaultValue": "",
|
||||
"description": "",
|
||||
"name": "runtimeScene",
|
||||
"optional": false,
|
||||
"supplementaryInformation": "",
|
||||
"type": "currentScene"
|
||||
}
|
||||
]
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"description": "Color the given sprite objects",
|
||||
"fullName": "Color sprites",
|
||||
"functionType": "Action",
|
||||
"name": "ColorThings",
|
||||
"sentence": "Color _PARAM1_",
|
||||
"sentence": "Color _PARAM1_ with color: _PARAM2_",
|
||||
"events": [
|
||||
{
|
||||
"disabled": false,
|
||||
@@ -5383,7 +5396,7 @@
|
||||
},
|
||||
"parameters": [
|
||||
"ObjectToColor",
|
||||
"\"0;255;50\""
|
||||
"GetArgumentAsString(\"Color\")"
|
||||
],
|
||||
"subInstructions": []
|
||||
}
|
||||
@@ -5392,15 +5405,6 @@
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"codeOnly": true,
|
||||
"defaultValue": "",
|
||||
"description": "",
|
||||
"name": "runtimeScene",
|
||||
"optional": false,
|
||||
"supplementaryInformation": "",
|
||||
"type": "currentScene"
|
||||
},
|
||||
{
|
||||
"codeOnly": false,
|
||||
"defaultValue": "",
|
||||
@@ -5409,6 +5413,15 @@
|
||||
"optional": false,
|
||||
"supplementaryInformation": "Sprite",
|
||||
"type": "objectList"
|
||||
},
|
||||
{
|
||||
"codeOnly": false,
|
||||
"defaultValue": "",
|
||||
"description": "Color string",
|
||||
"name": "Color",
|
||||
"optional": false,
|
||||
"supplementaryInformation": "",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
BIN
GDJS/tests/games/rotated-objects-hitboxes/Image-1.png
Normal file
After Width: | Height: | Size: 879 B |
BIN
GDJS/tests/games/rotated-objects-hitboxes/NewObject-1.png
Normal file
After Width: | Height: | Size: 567 B |
BIN
GDJS/tests/games/rotated-objects-hitboxes/NewObject2-1-0.png
Normal file
After Width: | Height: | Size: 156 B |
BIN
GDJS/tests/games/rotated-objects-hitboxes/NewObject2-1.png
Normal file
After Width: | Height: | Size: 156 B |
BIN
GDJS/tests/games/rotated-objects-hitboxes/NewObject2-2.png
Normal file
After Width: | Height: | Size: 312 B |
779
GDJS/tests/games/rotated-objects-hitboxes/game.json
Normal file
@@ -0,0 +1,779 @@
|
||||
{
|
||||
"firstLayout": "",
|
||||
"gdVersion": {
|
||||
"build": 97,
|
||||
"major": 4,
|
||||
"minor": 0,
|
||||
"revision": 0
|
||||
},
|
||||
"properties": {
|
||||
"folderProject": false,
|
||||
"linuxExecutableFilename": "",
|
||||
"macExecutableFilename": "",
|
||||
"orientation": "landscape",
|
||||
"packageName": "com.example.gamename",
|
||||
"projectFile": "/Users/florianrival/Projects/F/GD/GDJS/tests/games/rotated-objects-hitboxes/game.json",
|
||||
"sizeOnStartupMode": "adaptWidth",
|
||||
"useExternalSourceFiles": false,
|
||||
"version": "1.0.0",
|
||||
"winExecutableFilename": "",
|
||||
"winExecutableIconFile": "",
|
||||
"name": "Project",
|
||||
"author": "",
|
||||
"windowWidth": 800,
|
||||
"windowHeight": 600,
|
||||
"latestCompilationDirectory": "",
|
||||
"maxFPS": 60,
|
||||
"minFPS": 10,
|
||||
"verticalSync": false,
|
||||
"platformSpecificAssets": {},
|
||||
"loadingScreen": {
|
||||
"showGDevelopSplash": false
|
||||
},
|
||||
"extensions": [
|
||||
{
|
||||
"name": "BuiltinObject"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinAudio"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinVariables"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinTime"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinMouse"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinKeyboard"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinJoystick"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinCamera"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinWindow"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinFile"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinNetwork"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinScene"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinAdvanced"
|
||||
},
|
||||
{
|
||||
"name": "Sprite"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinCommonInstructions"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinCommonConversions"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinStringInstructions"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinMathematicalTools"
|
||||
},
|
||||
{
|
||||
"name": "BuiltinExternalLayouts"
|
||||
}
|
||||
],
|
||||
"platforms": [
|
||||
{
|
||||
"name": "GDevelop JS platform"
|
||||
}
|
||||
],
|
||||
"currentPlatform": "GDevelop JS platform"
|
||||
},
|
||||
"resources": {
|
||||
"resources": [
|
||||
{
|
||||
"alwaysLoaded": false,
|
||||
"file": "NewObject-1.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "NewObject-1.png",
|
||||
"smoothed": true,
|
||||
"userAdded": true
|
||||
},
|
||||
{
|
||||
"alwaysLoaded": false,
|
||||
"file": "NewObject2-1.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "NewObject2-1.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
},
|
||||
{
|
||||
"alwaysLoaded": false,
|
||||
"file": "Image-1.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "Image-1.png",
|
||||
"smoothed": true,
|
||||
"userAdded": true
|
||||
},
|
||||
{
|
||||
"alwaysLoaded": false,
|
||||
"file": "NewObject2-1-0.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "NewObject2-1-0.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
},
|
||||
{
|
||||
"alwaysLoaded": false,
|
||||
"file": "NewObject2-2.png",
|
||||
"kind": "image",
|
||||
"metadata": "",
|
||||
"name": "NewObject2-2.png",
|
||||
"smoothed": true,
|
||||
"userAdded": false
|
||||
}
|
||||
],
|
||||
"resourceFolders": []
|
||||
},
|
||||
"objects": [],
|
||||
"objectsGroups": [],
|
||||
"variables": [],
|
||||
"layouts": [
|
||||
{
|
||||
"b": 209,
|
||||
"disableInputWhenNotFocused": true,
|
||||
"mangledName": "NewScene",
|
||||
"name": "NewScene",
|
||||
"oglFOV": 90,
|
||||
"oglZFar": 500,
|
||||
"oglZNear": 1,
|
||||
"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
|
||||
},
|
||||
"objectsGroups": [],
|
||||
"variables": [],
|
||||
"instances": [
|
||||
{
|
||||
"angle": 45,
|
||||
"customSize": false,
|
||||
"height": 0,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "DefaultSprite",
|
||||
"width": 0,
|
||||
"x": 39,
|
||||
"y": 32,
|
||||
"zOrder": 1,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 45,
|
||||
"customSize": true,
|
||||
"height": 66,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "CenterTopLeft",
|
||||
"width": 107,
|
||||
"x": 80,
|
||||
"y": 219,
|
||||
"zOrder": 2,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 32.0054,
|
||||
"customSize": true,
|
||||
"height": 24,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "TextObject",
|
||||
"width": 136,
|
||||
"x": 346,
|
||||
"y": 51,
|
||||
"zOrder": 3,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 16.9908,
|
||||
"customSize": true,
|
||||
"height": 32,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "TiledSprite",
|
||||
"width": 349,
|
||||
"x": 452,
|
||||
"y": 61,
|
||||
"zOrder": 4,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 0,
|
||||
"customSize": true,
|
||||
"height": 48,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "CenterTopLeft",
|
||||
"width": 94,
|
||||
"x": 177,
|
||||
"y": 219,
|
||||
"zOrder": 2,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 44.3415,
|
||||
"customSize": true,
|
||||
"height": 72,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "CenterBottomRight",
|
||||
"width": 104,
|
||||
"x": 575,
|
||||
"y": 288,
|
||||
"zOrder": 5,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 0,
|
||||
"customSize": true,
|
||||
"height": 63,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "CenterBottomRight",
|
||||
"width": 101,
|
||||
"x": 433,
|
||||
"y": 254,
|
||||
"zOrder": 5,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 38.4969,
|
||||
"customSize": true,
|
||||
"height": 63,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "OriginMiddleCenterBottomRight",
|
||||
"width": 90,
|
||||
"x": 251,
|
||||
"y": 518,
|
||||
"zOrder": 6,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 0,
|
||||
"customSize": true,
|
||||
"height": 59,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "OriginMiddleCenterBottomRight",
|
||||
"width": 101,
|
||||
"x": 96,
|
||||
"y": 473,
|
||||
"zOrder": 6,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 0,
|
||||
"customSize": false,
|
||||
"height": 0,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "CenterTopLeft",
|
||||
"width": 0,
|
||||
"x": 177,
|
||||
"y": 171,
|
||||
"zOrder": 2,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 45,
|
||||
"customSize": false,
|
||||
"height": 0,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "CenterTopLeft",
|
||||
"width": 0,
|
||||
"x": 93,
|
||||
"y": 153,
|
||||
"zOrder": 2,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 0,
|
||||
"customSize": false,
|
||||
"height": 0,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "CenterBottomRight",
|
||||
"width": 0,
|
||||
"x": 434,
|
||||
"y": 193,
|
||||
"zOrder": 5,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 44.3415,
|
||||
"customSize": false,
|
||||
"height": 0,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "CenterBottomRight",
|
||||
"width": 0,
|
||||
"x": 552,
|
||||
"y": 193,
|
||||
"zOrder": 5,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 0,
|
||||
"customSize": false,
|
||||
"height": 0,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "OriginMiddleCenterBottomRight",
|
||||
"width": 0,
|
||||
"x": 77,
|
||||
"y": 414,
|
||||
"zOrder": 6,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 38.4969,
|
||||
"customSize": false,
|
||||
"height": 0,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "OriginMiddleCenterBottomRight",
|
||||
"width": 0,
|
||||
"x": 215,
|
||||
"y": 424,
|
||||
"zOrder": 6,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 45,
|
||||
"customSize": true,
|
||||
"height": 71,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "CustomHitboxesOriginMiddleCenterBottomRight",
|
||||
"width": 105,
|
||||
"x": 647,
|
||||
"y": 566,
|
||||
"zOrder": 7,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 0,
|
||||
"customSize": true,
|
||||
"height": 65,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "CustomHitboxesOriginMiddleCenterBottomRight",
|
||||
"width": 112,
|
||||
"x": 515,
|
||||
"y": 538,
|
||||
"zOrder": 7,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 45,
|
||||
"customSize": false,
|
||||
"height": 0,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "CustomHitboxesOriginMiddleCenterBottomRight",
|
||||
"width": 0,
|
||||
"x": 632,
|
||||
"y": 451,
|
||||
"zOrder": 7,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 0,
|
||||
"customSize": false,
|
||||
"height": 0,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "CustomHitboxesOriginMiddleCenterBottomRight",
|
||||
"width": 0,
|
||||
"x": 510.005,
|
||||
"y": 450.563,
|
||||
"zOrder": 7,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 32.0054,
|
||||
"customSize": false,
|
||||
"height": 0,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "TextObject",
|
||||
"width": 0,
|
||||
"x": 141,
|
||||
"y": 52,
|
||||
"zOrder": 3,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
},
|
||||
{
|
||||
"angle": 0,
|
||||
"customSize": true,
|
||||
"height": 24,
|
||||
"layer": "",
|
||||
"locked": false,
|
||||
"name": "TextObject",
|
||||
"width": 127,
|
||||
"x": 323,
|
||||
"y": 530,
|
||||
"zOrder": 8,
|
||||
"numberProperties": [],
|
||||
"stringProperties": [],
|
||||
"initialVariables": []
|
||||
}
|
||||
],
|
||||
"objects": [
|
||||
{
|
||||
"name": "DefaultSprite",
|
||||
"type": "Sprite",
|
||||
"updateIfNotVisible": false,
|
||||
"variables": [],
|
||||
"behaviors": [],
|
||||
"animations": [
|
||||
{
|
||||
"name": "NewObject",
|
||||
"useMultipleDirections": false,
|
||||
"directions": [
|
||||
{
|
||||
"looping": false,
|
||||
"timeBetweenFrames": 1,
|
||||
"sprites": [
|
||||
{
|
||||
"hasCustomCollisionMask": false,
|
||||
"image": "NewObject-1.png",
|
||||
"points": [],
|
||||
"originPoint": {
|
||||
"name": "origine",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"centerPoint": {
|
||||
"automatic": true,
|
||||
"name": "centre",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"customCollisionMask": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CenterBottomRight",
|
||||
"type": "Sprite",
|
||||
"updateIfNotVisible": false,
|
||||
"variables": [],
|
||||
"behaviors": [],
|
||||
"animations": [
|
||||
{
|
||||
"name": "NewObject2",
|
||||
"useMultipleDirections": false,
|
||||
"directions": [
|
||||
{
|
||||
"looping": false,
|
||||
"timeBetweenFrames": 1,
|
||||
"sprites": [
|
||||
{
|
||||
"hasCustomCollisionMask": false,
|
||||
"image": "NewObject2-1.png",
|
||||
"points": [],
|
||||
"originPoint": {
|
||||
"name": "origine",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"centerPoint": {
|
||||
"automatic": false,
|
||||
"name": "centre",
|
||||
"x": 64,
|
||||
"y": 31
|
||||
},
|
||||
"customCollisionMask": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CenterTopLeft",
|
||||
"type": "Sprite",
|
||||
"updateIfNotVisible": false,
|
||||
"variables": [],
|
||||
"behaviors": [],
|
||||
"animations": [
|
||||
{
|
||||
"name": "NewObject2",
|
||||
"useMultipleDirections": false,
|
||||
"directions": [
|
||||
{
|
||||
"looping": false,
|
||||
"timeBetweenFrames": 1,
|
||||
"sprites": [
|
||||
{
|
||||
"hasCustomCollisionMask": false,
|
||||
"image": "NewObject2-1.png",
|
||||
"points": [],
|
||||
"originPoint": {
|
||||
"name": "origine",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"centerPoint": {
|
||||
"automatic": false,
|
||||
"name": "centre",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"customCollisionMask": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"name": "TextObject",
|
||||
"smoothed": true,
|
||||
"type": "TextObject::Text",
|
||||
"underlined": false,
|
||||
"variables": [],
|
||||
"behaviors": [],
|
||||
"string": "Text blabl balbalbal",
|
||||
"font": "",
|
||||
"characterSize": 20,
|
||||
"color": {
|
||||
"b": 255,
|
||||
"g": 255,
|
||||
"r": 255
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "CustomHitboxesOriginMiddleCenterBottomRight",
|
||||
"type": "Sprite",
|
||||
"updateIfNotVisible": false,
|
||||
"variables": [],
|
||||
"behaviors": [],
|
||||
"animations": [
|
||||
{
|
||||
"name": "NewObject2",
|
||||
"useMultipleDirections": false,
|
||||
"directions": [
|
||||
{
|
||||
"looping": false,
|
||||
"timeBetweenFrames": 1,
|
||||
"sprites": [
|
||||
{
|
||||
"hasCustomCollisionMask": true,
|
||||
"image": "NewObject2-2.png",
|
||||
"points": [],
|
||||
"originPoint": {
|
||||
"name": "origine",
|
||||
"x": 32,
|
||||
"y": 16
|
||||
},
|
||||
"centerPoint": {
|
||||
"automatic": false,
|
||||
"name": "centre",
|
||||
"x": 64,
|
||||
"y": 31
|
||||
},
|
||||
"customCollisionMask": [
|
||||
[
|
||||
{
|
||||
"x": 12.5,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 41.5,
|
||||
"y": 2
|
||||
},
|
||||
{
|
||||
"x": 55.5,
|
||||
"y": 31
|
||||
},
|
||||
{
|
||||
"x": 24.5,
|
||||
"y": 30
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OriginMiddleCenterBottomRight",
|
||||
"type": "Sprite",
|
||||
"updateIfNotVisible": false,
|
||||
"variables": [],
|
||||
"behaviors": [],
|
||||
"animations": [
|
||||
{
|
||||
"name": "NewObject2",
|
||||
"useMultipleDirections": false,
|
||||
"directions": [
|
||||
{
|
||||
"looping": false,
|
||||
"timeBetweenFrames": 1,
|
||||
"sprites": [
|
||||
{
|
||||
"hasCustomCollisionMask": false,
|
||||
"image": "NewObject2-1.png",
|
||||
"points": [],
|
||||
"originPoint": {
|
||||
"name": "origine",
|
||||
"x": 32,
|
||||
"y": 16
|
||||
},
|
||||
"centerPoint": {
|
||||
"automatic": false,
|
||||
"name": "centre",
|
||||
"x": 64,
|
||||
"y": 31
|
||||
},
|
||||
"customCollisionMask": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"height": 32,
|
||||
"name": "TiledSprite",
|
||||
"texture": "Image-1.png",
|
||||
"type": "TiledSpriteObject::TiledSprite",
|
||||
"width": 32,
|
||||
"variables": [],
|
||||
"behaviors": []
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"disabled": false,
|
||||
"folded": false,
|
||||
"type": "BuiltinCommonInstructions::Comment",
|
||||
"color": {
|
||||
"b": 109,
|
||||
"g": 230,
|
||||
"r": 255,
|
||||
"textB": 0,
|
||||
"textG": 0,
|
||||
"textR": 0
|
||||
},
|
||||
"comment": "Verify the hitboxes of the objects, in particular the rotated ones and the ones with a center point and/or origin that is not at the default position, and/or that are scaled",
|
||||
"comment2": ""
|
||||
}
|
||||
],
|
||||
"layers": [
|
||||
{
|
||||
"name": "",
|
||||
"visibility": true,
|
||||
"cameras": [
|
||||
{
|
||||
"defaultSize": true,
|
||||
"defaultViewport": true,
|
||||
"height": 0,
|
||||
"viewportBottom": 1,
|
||||
"viewportLeft": 0,
|
||||
"viewportRight": 1,
|
||||
"viewportTop": 0,
|
||||
"width": 0
|
||||
}
|
||||
],
|
||||
"effects": []
|
||||
}
|
||||
],
|
||||
"behaviorsSharedData": []
|
||||
}
|
||||
],
|
||||
"externalEvents": [],
|
||||
"eventsFunctionsExtensions": [],
|
||||
"externalLayouts": [],
|
||||
"externalSourceFiles": []
|
||||
}
|
@@ -54,7 +54,11 @@ module.exports = function(config) {
|
||||
//All tests files:
|
||||
'./tests/init.js',
|
||||
'../../Extensions/**/tests/**.spec.js',
|
||||
'./tests/**/*.js'
|
||||
'./tests/**/*.js',
|
||||
|
||||
//All benchmark files:
|
||||
'./benchmarks/init.js',
|
||||
'./benchmarks/**/*.js'
|
||||
]
|
||||
});
|
||||
};
|
||||
|
16
GDJS/tests/tests/force.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Common tests for gdjs game engine.
|
||||
* See README.md for more information.
|
||||
*/
|
||||
|
||||
|
||||
describe('gdjs.Force', function() {
|
||||
it('can set angle and length', function(){
|
||||
var layer = new gdjs.Force();
|
||||
layer.setAngle(-45);
|
||||
layer.setLength(200);
|
||||
|
||||
expect(layer.getX()).to.be.within(141.42, 141.422);
|
||||
expect(layer.getY()).to.be.within(-141.422, -141.42);
|
||||
});
|
||||
});
|
29
GDJS/tests/tests/layer.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Common tests for gdjs game engine.
|
||||
* See README.md for more information.
|
||||
*/
|
||||
|
||||
|
||||
describe('gdjs.Layer', function() {
|
||||
var runtimeGame = new gdjs.RuntimeGame({variables: [], properties: {windowWidth: 800, windowHeight: 600}});
|
||||
var runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
|
||||
it('can convert coordinates', function(){
|
||||
var layer = new gdjs.Layer({name: 'My layer', visibility: true, effects:[]}, runtimeScene)
|
||||
layer.setCameraX(100, 0);
|
||||
layer.setCameraY(200, 0);
|
||||
layer.setCameraRotation(90, 0);
|
||||
|
||||
expect(layer.convertCoords(350, 450, 0)[0]).to.be.within(-50.001, -49.99999);
|
||||
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)
|
||||
layer.setCameraX(100, 0);
|
||||
layer.setCameraY(200, 0);
|
||||
layer.setCameraRotation(90, 0);
|
||||
|
||||
expect(layer.convertInverseCoords(350, 450, 0)[0]).to.be.within(649.999, 650.001);
|
||||
expect(layer.convertInverseCoords(350, 450, 0)[1]).to.be.within(49.9999, 50.001);
|
||||
});
|
||||
});
|
@@ -3,7 +3,7 @@
|
||||
* See README.md for more information.
|
||||
*/
|
||||
|
||||
describe('gdjs.runtimeObject', function() {
|
||||
describe('gdjs.RuntimeObject', function() {
|
||||
var runtimeScene = new gdjs.RuntimeScene(null);
|
||||
|
||||
it('should compute distances properly', function(){
|
||||
@@ -12,4 +12,42 @@ describe('gdjs.runtimeObject', function() {
|
||||
|
||||
expect(object.getSqDistanceTo(-110, 200)).to.be(48025);
|
||||
});
|
||||
|
||||
it('should compute AABB properly', function(){
|
||||
var object = new gdjs.RuntimeObject(runtimeScene, {name: "obj1", type: "", behaviors: []});
|
||||
object.getWidth = function() { return 10; };
|
||||
object.getHeight = function() { return 20; };
|
||||
|
||||
expect(object.getAABB()).to.eql({
|
||||
min: [0,0],
|
||||
max: [10,20]
|
||||
});
|
||||
|
||||
object.setPosition(15, 20);
|
||||
expect(object.getAABB()).to.eql({
|
||||
min: [15,20],
|
||||
max: [25,40]
|
||||
});
|
||||
|
||||
object.setAngle(90);
|
||||
expect(object.getAABB()).to.eql({
|
||||
min: [10,25],
|
||||
max: [30,35]
|
||||
});
|
||||
|
||||
object.setAngle(0);
|
||||
object.getCenterX = function() { return 0 };
|
||||
object.getCenterY = function() { return 0 };
|
||||
expect(object.getAABB()).to.eql({
|
||||
min: [15,20],
|
||||
max: [25,40]
|
||||
});
|
||||
|
||||
object.setPosition(15, 20);
|
||||
object.setAngle(90);
|
||||
expect(object.getAABB()).to.eql({
|
||||
min: [-5,20],
|
||||
max: [15,30]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -3,6 +3,64 @@
|
||||
* See README.md for more information.
|
||||
*/
|
||||
|
||||
const makeSpriteRuntimeObjectWithCustomHitBox = (runtimeScene) => new gdjs.SpriteRuntimeObject(runtimeScene, {
|
||||
"name": "obj1",
|
||||
"type": "Sprite",
|
||||
"updateIfNotVisible": false,
|
||||
"variables": [],
|
||||
"behaviors": [],
|
||||
"animations": [
|
||||
{
|
||||
"name": "NewObject2",
|
||||
"useMultipleDirections": false,
|
||||
"directions": [
|
||||
{
|
||||
"looping": false,
|
||||
"timeBetweenFrames": 1,
|
||||
"sprites": [
|
||||
{
|
||||
"hasCustomCollisionMask": true,
|
||||
"image": "NewObject2-2.png",
|
||||
"points": [],
|
||||
"originPoint": {
|
||||
"name": "origine",
|
||||
"x": 32,
|
||||
"y": 16
|
||||
},
|
||||
"centerPoint": {
|
||||
"automatic": false,
|
||||
"name": "centre",
|
||||
"x": 64,
|
||||
"y": 31
|
||||
},
|
||||
"customCollisionMask": [
|
||||
[
|
||||
{
|
||||
"x": 12.5,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 41.5,
|
||||
"y": 2
|
||||
},
|
||||
{
|
||||
"x": 55.5,
|
||||
"y": 31
|
||||
},
|
||||
{
|
||||
"x": 24.5,
|
||||
"y": 30
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
describe('gdjs.SpriteRuntimeObject', function() {
|
||||
var runtimeGame = new gdjs.RuntimeGame({variables: [], properties: {windowWidth: 800, windowHeight: 600}});
|
||||
var runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
@@ -61,4 +119,22 @@ describe('gdjs.SpriteRuntimeObject', function() {
|
||||
expect(object.getAnimationName()).to.be('firstAnimation');
|
||||
});
|
||||
});
|
||||
|
||||
it('should properly compute hitboxes', function(){
|
||||
// Create an object with a custom hitbox
|
||||
const object = makeSpriteRuntimeObjectWithCustomHitBox(runtimeScene);
|
||||
|
||||
// Check the hitboxes without any rotation (only the non default origin
|
||||
// which is at 32;16 is to be used).
|
||||
expect(object.getHitBoxes()[0].vertices[0]).to.eql([12.5 - 32, 1 - 16]);
|
||||
expect(object.getHitBoxes()[0].vertices[1]).to.eql([41.5 - 32, 2 - 16]);
|
||||
expect(object.getHitBoxes()[0].vertices[2]).to.eql([55.5 - 32, 31 - 16]);
|
||||
expect(object.getHitBoxes()[0].vertices[3]).to.eql([24.5 - 32, 30 - 16]);
|
||||
|
||||
object.setAngle(90);
|
||||
expect(object.getHitBoxes()[0].vertices[0][0]).to.be.within(61.9999, 62.0001);
|
||||
expect(object.getHitBoxes()[0].vertices[0][1]).to.be.within(-36.5001, -36.49999);
|
||||
expect(object.getHitBoxes()[0].vertices[2][0]).to.be.within(31.999, 32.0001);
|
||||
expect(object.getHitBoxes()[0].vertices[2][1]).to.be.within(6.4999, 6.5001);
|
||||
});
|
||||
});
|
||||
|
2
newIDE/app/.gitignore
vendored
@@ -23,7 +23,7 @@ public/libGD.js
|
||||
public/external/Piskel/piskel-editor
|
||||
public/external/Piskel/piskel-editor.zip
|
||||
public/external/monaco-editor-min
|
||||
public/external/jsfx/loov-jsfx/
|
||||
public/external/jfxr/jfxr-editor/
|
||||
|
||||
# Resources
|
||||
public/res
|
||||
|
@@ -29,7 +29,6 @@
|
||||
"i18next": "^10.0.3",
|
||||
"keen-tracking": "1.1.3",
|
||||
"lodash": "4.17.4",
|
||||
"loov-jsfx": "1.2.0",
|
||||
"material-ui": "0.20",
|
||||
"material-ui-search-bar": "0.4.1",
|
||||
"node-require-function": "^1.2.0",
|
||||
@@ -61,7 +60,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "npm run import-resources",
|
||||
"import-resources": "cd scripts && node import-libGD.js && node import-res-folder.js && node import-GDJS-Runtime.js && node import-piskel-editor.js && node import-monaco-editor.js && node import-jsfx-editor.js",
|
||||
"import-resources": "cd scripts && node import-libGD.js && node import-res-folder.js && node import-GDJS-Runtime.js && node import-monaco-editor.js && node import-zipped-editor.js piskel 5.0.0-beta34 && node import-zipped-editor.js jfxr 5.0.0-beta55",
|
||||
"start": "npm run import-resources && react-scripts start",
|
||||
"build": "npm run import-resources && react-scripts build",
|
||||
"format": "prettier --write \"src/**/*.js\"",
|
||||
|
7
newIDE/app/public/external/jfxr/README.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
This folder contains sources to embed Jfxr editor (https://github.com/ttencate/jfxr) so that it can
|
||||
be used directly from GDevelop to edit sound effects.
|
||||
|
||||
Jfxr sources are downloaded by `import-zipped-editor.js` script. They are raw, unchanged sources
|
||||
of the Jfxr editor build. Sources will be stored in `Jfxr-editor` folder.
|
||||
See `jfxr-main.js` for the code running the editor.
|
||||
See `ModalWindow.js` and `LocalJfxrBridge.js` files for the bridge that open the Window and pass data from GDevelop to Jfxr.
|
14
newIDE/app/public/external/jfxr/jfxr-index.html
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>GDevelop Jfxr Editor</title>
|
||||
<link rel="stylesheet" type="text/css" href="jfxr-style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id='path-editor-header'></div>
|
||||
<iframe id='jfxr-frame'></iframe>
|
||||
<script type="module" src="gdide://external/jfxr/jfxr-main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
88
newIDE/app/public/external/jfxr/jfxr-main.js
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
import { createPathEditorHeader } from '../utils/path-editor.js'
|
||||
|
||||
const electron = require('electron')
|
||||
const ipcRenderer = electron.ipcRenderer
|
||||
const fs = require('fs')
|
||||
const remote = electron.remote
|
||||
|
||||
let jfxr = null
|
||||
|
||||
const closeWindow = () => {
|
||||
remote.getCurrentWindow().close()
|
||||
}
|
||||
|
||||
const loadMetaData = metaData => {
|
||||
if ('jfxr' in metaData) {
|
||||
jfxr.getSound().parse(metaData.jfxr.data);
|
||||
} else {
|
||||
jfxr.applyPreset(jfxr.presets[1])
|
||||
}
|
||||
}
|
||||
|
||||
const saveSoundEffect = pathEditor => {
|
||||
const metadata = {
|
||||
data: jfxr.getSound().serialize(),
|
||||
name: pathEditor.state.name
|
||||
}
|
||||
|
||||
jfxr.synth.run().then(data => {
|
||||
var blob = new Blob([data.toWavBytes()], {
|
||||
type: 'audio/wav'
|
||||
})
|
||||
var fileReader = new FileReader()
|
||||
fileReader.onload = function () {
|
||||
fs.writeFileSync(pathEditor.state.fullPath, Buffer(new Uint8Array(this.result)))
|
||||
ipcRenderer.send('jfxr-changes-saved', pathEditor.state.fullPath, metadata)
|
||||
closeWindow()
|
||||
}
|
||||
fileReader.readAsArrayBuffer(blob)
|
||||
})
|
||||
}
|
||||
|
||||
// Gain access to JFXR controller by using the signal that the JFXR author kindly provided.
|
||||
// It gets fired upon loading of jfxr in the iframe element
|
||||
const editorFrameEl = document.getElementById('jfxr-frame')
|
||||
window.addEventListener('jfxrReady', (e) => {
|
||||
jfxr = e.mainCtrl;
|
||||
ipcRenderer.send('jfxr-ready');
|
||||
});
|
||||
// Trigger the load of Jfxr manually, to ensure the event listener "jfxrReady" is registered already
|
||||
editorFrameEl.src = 'jfxr-editor/index.html'
|
||||
|
||||
// Called to load a sound. Should be called after the window is fully loaded.
|
||||
ipcRenderer.on('jfxr-open', (event, receivedOptions) => {
|
||||
loadMetaData(receivedOptions.metadata);
|
||||
|
||||
// Load a custom save file(s) header
|
||||
const pathEditorHeaderDiv = document.getElementById('path-editor-header');
|
||||
const headerStyle = {
|
||||
saveFolderLabel: 'float: left;margin-left: 2px; font-size:15px;margin-top: 10px;color:aqua',
|
||||
nameInput: 'font-family:"Courier New";height:27px;width:90px;float:left;margin-left: 2px;padding:4px;margin-top: 4px;font-size:15px;border: 2px solid #e5cd50;border-radius: 3px;background-color:black; color: #e5cd50;',
|
||||
saveButton: 'float:right;margin-left:2px;margin-right:4px;border: 2px solid white;border-radius: 1px;margin-top: 5px;background-color:white;',
|
||||
cancelButton: 'float:right;margin-right:2px;border: 2px solid white;border-radius: 1px;margin-top: 5px;background-color:white;',
|
||||
setFolderButton: 'float:right;margin-left:2px;margin-right:4px;border: 2px solid white;border-radius: 1px;margin-top: 5px;background-color:white;',
|
||||
fileExistsLabel: 'height:27px;color:blue;float: left;margin-left: 2px;margin-top: 10px; font-size:15px;'
|
||||
};
|
||||
createPathEditorHeader({
|
||||
parentElement: pathEditorHeaderDiv,
|
||||
editorContentDocument: document,
|
||||
onSaveToGd: saveSoundEffect,
|
||||
onCancelChanges: closeWindow,
|
||||
projectPath: receivedOptions.projectPath,
|
||||
initialResourcePath: receivedOptions.resourcePath,
|
||||
extension: '.wav',
|
||||
headerStyle
|
||||
});
|
||||
// Disable google analytics from collecting personal information
|
||||
editorFrameEl.contentWindow.ga('set', 'allowAdFeatures', false);
|
||||
// Alter the interface of the external editor
|
||||
const editorContentDocument = editorFrameEl.contentDocument;
|
||||
editorContentDocument.getElementsByClassName('github')[0].remove();
|
||||
// Disable inside iframe links - they break the embedding
|
||||
editorContentDocument.getElementsByClassName('titlepane column-left')[0].childNodes[0].onclick = () => {
|
||||
return false
|
||||
};
|
||||
editorContentDocument.getElementsByClassName('titlepane column-left')[0].childNodes[1].onclick = () => {
|
||||
return false
|
||||
};
|
||||
})
|
@@ -7,10 +7,10 @@ body {
|
||||
font-family: Helvetica;
|
||||
margin: 0;
|
||||
overflow-y: hidden;
|
||||
background-color: white;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
#jsfx-frame {
|
||||
#jfxr-frame {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
7
newIDE/app/public/external/jsfx/README.md
vendored
@@ -1,7 +0,0 @@
|
||||
This folder contains sources to embed Jsfx editor (https://github.com/loov/jsfx/) so that it can
|
||||
be used directly from GDevelop to create sound effects.
|
||||
|
||||
Jsfx sources are copied by `import-jsfx-editor.js` script. They are raw, unchanged sources
|
||||
of the Jsfx editor. Sources will be stored in `loov-jsfx` folder.
|
||||
See `jsfx-main.js` for the code running the editor.
|
||||
See `ModalWindow.js` and `LocalJsfxBridge.js` files for the bridge that open the Window and pass data from GDevelop to Jsfx.
|
14
newIDE/app/public/external/jsfx/jsfx-index.html
vendored
@@ -1,14 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>GDevelop Jsfx Editor</title>
|
||||
<link rel="stylesheet" type="text/css" href="jsfx-style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id='path-editor-header'></div>
|
||||
<iframe id='jsfx-frame' src="loov-jsfx/index.html"></iframe>
|
||||
<script type="module" src="gdide://external/jsfx/jsfx-main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
111
newIDE/app/public/external/jsfx/jsfx-main.js
vendored
@@ -1,111 +0,0 @@
|
||||
import { createPathEditorHeader } from '../utils/path-editor.js';
|
||||
|
||||
const electron = require('electron');
|
||||
const ipcRenderer = electron.ipcRenderer;
|
||||
const fs = require('fs');
|
||||
const remote = electron.remote;
|
||||
|
||||
let editorContentDocument,
|
||||
jsfx = null;
|
||||
|
||||
const loadMetaData = metaData => {
|
||||
jsfx.CurrentParams = metaData;
|
||||
jsfx.UpdateCurrentView();
|
||||
jsfx.PlayCurrent();
|
||||
};
|
||||
|
||||
const closeWindow = () => {
|
||||
remote.getCurrentWindow().close();
|
||||
};
|
||||
|
||||
const saveSoundEffect = pathEditor => {
|
||||
jsfx.UpdateDownloadLink(); //Update base64 data
|
||||
const rawData = editorContentDocument
|
||||
.getElementById('download')
|
||||
.href.replace(/^data:audio\/wav;base64,/, '');
|
||||
fs.writeFile(pathEditor.state.fullPath, rawData, 'base64', err => {
|
||||
ipcRenderer.send(
|
||||
'jsfx-changes-saved',
|
||||
pathEditor.state.fullPath,
|
||||
jsfx.CurrentParams
|
||||
);
|
||||
closeWindow();
|
||||
});
|
||||
};
|
||||
|
||||
// Wait for the window to be fully initialized before sending the
|
||||
// ready event. Don't use DOMContentLoaded as it was observed to be fired
|
||||
// even if jsfx DOM/scripts are not yet loaded.
|
||||
window.addEventListener('load', function() {
|
||||
ipcRenderer.send('jsfx-ready');
|
||||
});
|
||||
|
||||
// Called to load a sound. Should be called after the window is fully loaded.
|
||||
ipcRenderer.on('jsfx-open', (event, receivedOptions) => {
|
||||
const editorFrameEl = document.getElementById('jsfx-frame');
|
||||
jsfx = editorFrameEl.contentWindow;
|
||||
editorContentDocument = editorFrameEl.contentDocument;
|
||||
const presetsPanel = editorContentDocument.getElementById('presets');
|
||||
|
||||
// Load metadata, if it exists
|
||||
if ('jsfx' in receivedOptions.metadata) {
|
||||
loadMetaData(receivedOptions.metadata.jsfx);
|
||||
} else {
|
||||
// If not, simulate a click on the 'Lucky' button to create a random sound effect
|
||||
const generateRandomSoundEffectButton = presetsPanel.childNodes[11];
|
||||
generateRandomSoundEffectButton.click();
|
||||
}
|
||||
// load a custom header
|
||||
const pathEditorHeaderDiv = document.getElementById('path-editor-header');
|
||||
const headerStyle = {
|
||||
saveFolderLabel:
|
||||
'height:27px;color:SlateGrey;float: left;margin-left: 2px;margin-top: 10px; font-size:15px;',
|
||||
nameInput:
|
||||
'font-family:"Courier New";height:27px;width:90px;color:SlateGrey;float:left;margin-left: 2px;padding:4px;margin-top: 4px;font-size:15px;border: 2px solid #e5cd50;border-radius: 3px; ',
|
||||
fileExistsLabel:
|
||||
'height:27px;color:blue;float: left;margin-left: 2px;margin-top: 10px; font-size:15px;',
|
||||
saveButton:
|
||||
'height:27px;float:right;margin-left:2px;margin-right:4px;border: 2px solid DeepSkyBlue;border-radius: 1px;margin-top: 5px;background-color:white;',
|
||||
cancelButton:
|
||||
'height:27px;float:right;margin-right:2px;border: 2px solid DeepSkyBlue;border-radius: 1px;margin-top: 5px;background-color:white;',
|
||||
setFolderButton:
|
||||
'height:27px;float:right;margin-left:2px;margin-right:4px;border: 2px solid DeepSkyBlue;border-radius: 1px;margin-top: 5px;background-color:white;',
|
||||
};
|
||||
createPathEditorHeader({
|
||||
parentElement: pathEditorHeaderDiv,
|
||||
editorContentDocument: document,
|
||||
onSaveToGd: saveSoundEffect,
|
||||
onCancelChanges: closeWindow,
|
||||
projectPath: receivedOptions.projectPath,
|
||||
initialResourcePath: receivedOptions.resourcePath,
|
||||
extension: '.wav',
|
||||
headerStyle,
|
||||
});
|
||||
|
||||
// alter the interface of the external editor
|
||||
editorContentDocument.getElementById('jsfx').firstChild.style = 'float:top';
|
||||
const defaultTitle = editorContentDocument.getElementsByClassName('title')[0]
|
||||
.firstChild;
|
||||
defaultTitle.remove();
|
||||
|
||||
presetsPanel.className = 'description';
|
||||
presetsPanel.style = 'float:left;';
|
||||
|
||||
const generatorsTitle = editorContentDocument.getElementsByClassName(
|
||||
'panel-title'
|
||||
)[1].firstChild;
|
||||
generatorsTitle.data = 'Create a Random Sound Effect:';
|
||||
|
||||
const description = editorContentDocument.getElementsByClassName(
|
||||
'description'
|
||||
)[0];
|
||||
description.remove();
|
||||
|
||||
const libraryPanel = editorContentDocument.getElementsByClassName(
|
||||
'panel wide'
|
||||
)[0];
|
||||
libraryPanel.style = 'visibility:hidden;height:0px;width:0px';
|
||||
|
||||
const defaultButtons = editorContentDocument.getElementById('control');
|
||||
defaultButtons.style = 'visibility:hidden;height:0px;width:0px';
|
||||
});
|
4
newIDE/app/public/external/piskel/README.md
vendored
@@ -1,7 +1,7 @@
|
||||
This folder contains sources to embed Piskel editor (https://www.piskelapp.com/) so that it can
|
||||
be used directly from GDevelop to edit images.
|
||||
|
||||
Piskel sources are downloaded by `import-piskel-editor.js` script. They are raw, unchanged sources
|
||||
of the Piskel editor. Sources will be stored in `piskel-editor` folder.
|
||||
Piskel sources are downloaded by `import-zipped-editor.js` script. They are raw, unchanged sources
|
||||
of the Piskel editor build. Sources will be stored in `piskel-editor` folder.
|
||||
See `piskel-main.js` for the code running the editor.
|
||||
See `ModalWindow.js` and `LocalPiskelBridge.js` files for the bridge that open the Window and pass data from GDevelop to Piskel.
|
||||
|
38
newIDE/app/public/external/utils/path-editor.js
vendored
@@ -1,9 +1,8 @@
|
||||
const electron = require('electron');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const remote = electron.remote;
|
||||
const {
|
||||
dialog
|
||||
} = remote;
|
||||
const { dialog } = remote;
|
||||
|
||||
export const createPathEditorHeader = ({
|
||||
parentElement,
|
||||
@@ -15,25 +14,21 @@ export const createPathEditorHeader = ({
|
||||
extension,
|
||||
headerStyle,
|
||||
}) => {
|
||||
if (fs.lstatSync(initialResourcePath).isDirectory()) {
|
||||
initialResourcePath = initialResourcePath + '/NewFile' + extension;
|
||||
if (fs.existsSync(initialResourcePath)) {
|
||||
if (fs.lstatSync(initialResourcePath).isDirectory()) {
|
||||
initialResourcePath = initialResourcePath + '/NewFile' + extension;
|
||||
}
|
||||
} else {
|
||||
initialResourcePath = projectPath + '/NewFile' + extension;
|
||||
}
|
||||
|
||||
initialResourcePath = path.normalize(initialResourcePath)
|
||||
const headerObject = {
|
||||
state: {
|
||||
folderPath: initialResourcePath.substring(
|
||||
0,
|
||||
initialResourcePath.lastIndexOf('/')
|
||||
),
|
||||
name: initialResourcePath.substring(
|
||||
initialResourcePath.lastIndexOf('/') + 1,
|
||||
initialResourcePath.lastIndexOf('.')
|
||||
),
|
||||
extension: initialResourcePath.substring(
|
||||
initialResourcePath.lastIndexOf('.'),
|
||||
initialResourcePath.length
|
||||
),
|
||||
projectBasePath: projectPath,
|
||||
folderPath: path.dirname(initialResourcePath),
|
||||
name: path.basename(initialResourcePath, path.extname(initialResourcePath)),
|
||||
extension: path.extname(initialResourcePath),
|
||||
projectBasePath: path.normalize(projectPath),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -124,15 +119,16 @@ const selectBaseFolderPath = headerObject => {
|
||||
if (!selectedDir) {
|
||||
return;
|
||||
}
|
||||
if (!selectedDir.toString().startsWith(state.projectBasePath)) {
|
||||
const selectedDirPath = selectedDir[0];
|
||||
if (!selectedDirPath.startsWith(state.projectBasePath)) {
|
||||
alert(
|
||||
'Please select a folder inside your project path!\n' +
|
||||
state.projectBasePath +
|
||||
'\n\nSelected:\n' +
|
||||
selectedDir
|
||||
selectedDirPath
|
||||
);
|
||||
return;
|
||||
}
|
||||
state.folderPath = selectedDir;
|
||||
state.folderPath = selectedDirPath;
|
||||
render(headerObject);
|
||||
};
|
BIN
newIDE/app/resources/examples/admob/Button.png
Executable file
After Width: | Height: | Size: 184 B |
BIN
newIDE/app/resources/examples/admob/Grass.png
Executable file
After Width: | Height: | Size: 1.0 KiB |
1
newIDE/app/resources/examples/admob/README.md
Normal file
@@ -0,0 +1 @@
|
||||
Demonstrate how to show ads from AdMob in your game: banners, interstitial screen or reward videos. Also useful to test that your AdMob account is working properly.
|
4925
newIDE/app/resources/examples/admob/admob.json
Executable file
BIN
newIDE/app/resources/examples/admob/android-icon-144.png
Executable file
After Width: | Height: | Size: 10 KiB |
BIN
newIDE/app/resources/examples/admob/android-icon-192.png
Executable file
After Width: | Height: | Size: 15 KiB |
BIN
newIDE/app/resources/examples/admob/android-icon-36.png
Executable file
After Width: | Height: | Size: 1.5 KiB |
BIN
newIDE/app/resources/examples/admob/android-icon-48.png
Executable file
After Width: | Height: | Size: 2.2 KiB |
BIN
newIDE/app/resources/examples/admob/android-icon-72.png
Executable file
After Width: | Height: | Size: 3.8 KiB |
BIN
newIDE/app/resources/examples/admob/android-icon-96.png
Executable file
After Width: | Height: | Size: 5.8 KiB |
BIN
newIDE/app/resources/examples/admob/desktop-icon-512.png
Executable file
After Width: | Height: | Size: 61 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-100.png
Executable file
After Width: | Height: | Size: 6.1 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-114.png
Executable file
After Width: | Height: | Size: 7.4 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-120.png
Executable file
After Width: | Height: | Size: 7.9 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-144.png
Executable file
After Width: | Height: | Size: 10 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-152.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-167.png
Executable file
After Width: | Height: | Size: 12 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-180.png
Executable file
After Width: | Height: | Size: 14 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-29.png
Executable file
After Width: | Height: | Size: 1.2 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-40.png
Executable file
After Width: | Height: | Size: 1.8 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-50.png
Executable file
After Width: | Height: | Size: 2.3 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-57.png
Executable file
After Width: | Height: | Size: 2.8 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-58.png
Executable file
After Width: | Height: | Size: 2.9 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-60.png
Executable file
After Width: | Height: | Size: 2.9 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-72.png
Executable file
After Width: | Height: | Size: 3.8 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-76.png
Executable file
After Width: | Height: | Size: 4.1 KiB |
BIN
newIDE/app/resources/examples/admob/ios-icon-80.png
Executable file
After Width: | Height: | Size: 4.4 KiB |
BIN
newIDE/app/resources/examples/admob/player.png
Executable file
After Width: | Height: | Size: 483 B |
@@ -1,14 +0,0 @@
|
||||
var shell = require('shelljs');
|
||||
|
||||
var source = '../node_modules/loov-jsfx';
|
||||
|
||||
var success = true;
|
||||
success &= !shell.mkdir('-p', '../public/external/jsfx').stderr;
|
||||
success &= !shell.cp('-Rf', source, '../public/external/jsfx').stderr;
|
||||
if (!success) {
|
||||
shell.echo(
|
||||
`❌ Error(s) occurred while copying Jsfx Editor sources from node_modules/loov-jsfx`
|
||||
);
|
||||
} else {
|
||||
shell.echo('✅ Sources of Jsfx Editor properly copied in public folder');
|
||||
}
|
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* This script download and extract a zipped version of the Piskel editor
|
||||
* (https://www.piskelapp.com/).
|
||||
* The zip file contains the raw, unchanged piskel editor sources into a folder
|
||||
* called "piskel-editor".
|
||||
*/
|
||||
var shell = require('shelljs');
|
||||
var https = require('follow-redirects').https;
|
||||
var fs = require('fs');
|
||||
var unzip2 = require('unzip2');
|
||||
|
||||
const zipFilePath = '../public/external/piskel/piskel-editor.zip';
|
||||
|
||||
if (shell.test('-d', '../public/external/piskel/piskel-editor')) {
|
||||
//Nothing to do
|
||||
shell.echo(
|
||||
'✅ piskel-editor already existing in public/external/piskel folder - skipping download'
|
||||
);
|
||||
} else {
|
||||
shell.echo(
|
||||
'🌐 Unable to find piskel-editor, downloading it from github.com/4ian/GD (be patient)...'
|
||||
);
|
||||
|
||||
var file = fs.createWriteStream(zipFilePath);
|
||||
https.get(
|
||||
'https://github.com/4ian/GDevelop/releases/download/v5.0.0-beta34/piskel-editor.zip',
|
||||
function(response) {
|
||||
if (response.statusCode !== 200) {
|
||||
shell.echo(
|
||||
`❌ Can't download piskel-editor.zip (${response.statusMessage}), please check your internet connection`
|
||||
);
|
||||
shell.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
response.pipe(file).on('finish', function() {
|
||||
shell.echo(
|
||||
'📂 Extracting piskel-editor.zip to public/external/piskel folder'
|
||||
);
|
||||
|
||||
try {
|
||||
fs
|
||||
.createReadStream(zipFilePath)
|
||||
.pipe(unzip2.Extract({ path: '../public/external/piskel' }))
|
||||
.on('close', function() {
|
||||
shell.echo(
|
||||
'✅ Extracted piskel-editor.zip to public/external/piskel folder'
|
||||
);
|
||||
shell.rm(zipFilePath);
|
||||
if (
|
||||
!shell.test('-d', '../public/external/piskel/piskel-editor')
|
||||
) {
|
||||
shell.echo(
|
||||
"❌ Can't verify that piskel-editor exists. Was the piskel-editor.zip file malformed?"
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
shell.echo(
|
||||
'❌ Error while extracting piskel-editor.zip to public/external/piskel folder:',
|
||||
e.message
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
73
newIDE/app/scripts/import-zipped-editor.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* This script will download and extract a zipped version of a prebuilt external html5 editor
|
||||
* The zip file contains the raw, unchanged editor sources, which will be extracted into a folder
|
||||
* The zip should be uploaded with one of the git releases (use gitRelease variable for version where you released it)
|
||||
*/
|
||||
var shell = require('shelljs');
|
||||
var https = require('follow-redirects').https;
|
||||
var fs = require('fs');
|
||||
var unzip2 = require('unzip2');
|
||||
var process = require('process')
|
||||
|
||||
const editor = process.argv[2];
|
||||
const gitRelease = process.argv[3];
|
||||
const gitUrl = 'https://github.com/4ian/GDevelop';
|
||||
const basePath = '../public/external/' + editor + '/' + editor + '-editor';
|
||||
const zipFilePath = basePath + '.zip';
|
||||
|
||||
if (shell.test('-d', basePath)) {
|
||||
//Nothing to do
|
||||
shell.echo(
|
||||
'✅ ' + editor + '-editor already existing in public/external/' + editor + ' folder - skipping download'
|
||||
);
|
||||
} else {
|
||||
shell.echo(
|
||||
'🌐 Unable to find ' + editor + '-editor, downloading it from ' + gitUrl + ' (be patient)...'
|
||||
);
|
||||
|
||||
var file = fs.createWriteStream(zipFilePath);
|
||||
https.get(
|
||||
gitUrl + '/releases/download/v' + gitRelease + '/' + editor + '-editor.zip',
|
||||
function (response) {
|
||||
if (response.statusCode !== 200) {
|
||||
shell.echo(
|
||||
`❌ Can't download ` + editor + `-editor.zip (${response.statusMessage}), please check your internet connection`
|
||||
);
|
||||
shell.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
response.pipe(file).on('finish', function () {
|
||||
shell.echo(
|
||||
'📂 Extracting ' + editor + '-editor.zip to public/external/' + editor + ' folder'
|
||||
);
|
||||
|
||||
try {
|
||||
fs
|
||||
.createReadStream(zipFilePath)
|
||||
.pipe(unzip2.Extract({
|
||||
path: '../public/external/' + editor
|
||||
}))
|
||||
.on('close', function () {
|
||||
shell.echo(
|
||||
'✅ Extracted ' + editor + '-editor.zip to public/external/' + editor + ' folder'
|
||||
);
|
||||
shell.rm(zipFilePath);
|
||||
if (
|
||||
!shell.test('-d', basePath)
|
||||
) {
|
||||
shell.echo(
|
||||
"❌ Can't verify that " + editor + "-editor exists. Was the " + editor + "-editor.zip file malformed?"
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
shell.echo(
|
||||
'❌ Error while extracting ' + editor + '-editor.zip to public/external/' + editor + ' folder:',
|
||||
e.message
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
@@ -14,9 +14,11 @@ import {
|
||||
enumerateObjectTypes,
|
||||
type EnumeratedObjectMetadata,
|
||||
} from '../ObjectsList/EnumerateObjects';
|
||||
import Divider from 'material-ui/Divider';
|
||||
import ThemeConsumer from '../UI/Theme/ThemeConsumer';
|
||||
import HelpButton from '../UI/HelpButton';
|
||||
import SemiControlledTextField from '../UI/SemiControlledTextField';
|
||||
import MiniToolbar, { MiniToolbarText } from '../UI/MiniToolbar';
|
||||
import { showWarningBox } from '../UI/Messages/MessageBox';
|
||||
|
||||
const gd = global.gd;
|
||||
|
||||
type Props = {|
|
||||
@@ -43,6 +45,17 @@ const styles = {
|
||||
},
|
||||
};
|
||||
|
||||
const validateParameterName = (newName: string) => {
|
||||
if (!gd.Project.validateObjectName(newName)) {
|
||||
showWarningBox(
|
||||
'This name contains forbidden characters: please only use alphanumeric characters (0-9, a-z) and underscores in your parameter name.'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
export default class EventsFunctionConfigurationEditor extends React.Component<
|
||||
Props,
|
||||
State
|
||||
@@ -150,143 +163,134 @@ export default class EventsFunctionConfigurationEditor extends React.Component<
|
||||
</Line>
|
||||
</Column>
|
||||
<Line noMargin>
|
||||
<ThemeConsumer>
|
||||
{muiTheme => (
|
||||
<div
|
||||
style={{
|
||||
...styles.parametersContainer,
|
||||
backgroundColor: muiTheme.list.itemsBackgroundColor,
|
||||
}}
|
||||
>
|
||||
{mapVector(
|
||||
parameters,
|
||||
(parameter: gdParameterMetadata, i: number) => (
|
||||
<React.Fragment key={i}>
|
||||
<Column>
|
||||
<Line noMargin expand>
|
||||
<Column noMargin expand>
|
||||
<TextField
|
||||
hintText="Parameter name"
|
||||
value={parameter.getName()}
|
||||
onChange={(e, text) => {
|
||||
parameter.setName(text);
|
||||
this.forceUpdate();
|
||||
}}
|
||||
onBlur={() => {
|
||||
this.props.onParametersUpdated();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
</Column>
|
||||
<Column noMargin expand>
|
||||
<SelectField
|
||||
hintText="Type"
|
||||
value={parameter.getType()}
|
||||
onChange={(e, i, value) => {
|
||||
parameter.setType(value);
|
||||
this.forceUpdate();
|
||||
this.props.onParametersUpdated();
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<MenuItem
|
||||
value="objectList"
|
||||
primaryText="Objects"
|
||||
/>
|
||||
<MenuItem
|
||||
value="expression"
|
||||
primaryText="Number"
|
||||
/>
|
||||
<MenuItem
|
||||
value="string"
|
||||
primaryText="String (text)"
|
||||
/>
|
||||
</SelectField>
|
||||
</Column>
|
||||
{parameter.getType() === 'objectList' && (
|
||||
<Column noMargin expand>
|
||||
<SelectField
|
||||
value={parameter.getExtraInfo()}
|
||||
onChange={(e, i, value) => {
|
||||
parameter.setExtraInfo(value);
|
||||
this.forceUpdate();
|
||||
this.props.onParametersUpdated();
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<MenuItem value="" primaryText="Any object" />
|
||||
{objectMetadata.map(
|
||||
(metadata: EnumeratedObjectMetadata) => {
|
||||
if (metadata.name === '') {
|
||||
// Base object is an "abstract" object
|
||||
return null;
|
||||
}
|
||||
<div style={styles.parametersContainer}>
|
||||
{mapVector(
|
||||
parameters,
|
||||
(parameter: gdParameterMetadata, i: number) => (
|
||||
<React.Fragment key={i}>
|
||||
<MiniToolbar>
|
||||
<MiniToolbarText>Parameter #{i + 1}:</MiniToolbarText>
|
||||
<Column expand noMargin>
|
||||
<SemiControlledTextField
|
||||
hintText="Enter the parameter name"
|
||||
value={parameter.getName()}
|
||||
onChange={text => {
|
||||
if (!validateParameterName(text)) return;
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
key={metadata.name}
|
||||
value={metadata.name}
|
||||
primaryText={metadata.fullName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</SelectField>
|
||||
</Column>
|
||||
)}
|
||||
</Line>
|
||||
</Column>
|
||||
<Line expand noMargin>
|
||||
<Column expand>
|
||||
<TextField
|
||||
hintText="Description"
|
||||
value={parameter.getDescription()}
|
||||
onChange={(e, text) => {
|
||||
parameter.setDescription(text);
|
||||
this.forceUpdate();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
</Column>
|
||||
<Column>
|
||||
<IconMenu
|
||||
iconButtonElement={
|
||||
<IconButton>
|
||||
<MoreVertIcon />
|
||||
</IconButton>
|
||||
}
|
||||
buildMenuTemplate={() => [
|
||||
{
|
||||
label: 'Delete',
|
||||
click: () => this._removeParameter(i),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Column>
|
||||
</Line>
|
||||
<Divider />
|
||||
</React.Fragment>
|
||||
)
|
||||
)}
|
||||
{parameters.size() <= 1 ? (
|
||||
<EmptyMessage>
|
||||
No parameters for this function.
|
||||
</EmptyMessage>
|
||||
) : null}
|
||||
<Line justifyContent="space-between">
|
||||
<Column>
|
||||
<HelpButton helpPagePath="/events/functions" />
|
||||
</Column>
|
||||
<Column>
|
||||
<FlatButton
|
||||
label="Add a parameter"
|
||||
onClick={this._addParameter}
|
||||
parameter.setName(text);
|
||||
this.forceUpdate();
|
||||
this.props.onParametersUpdated();
|
||||
}}
|
||||
commitOnBlur
|
||||
/>
|
||||
</Column>
|
||||
<IconMenu
|
||||
iconButtonElement={
|
||||
<IconButton>
|
||||
<MoreVertIcon />
|
||||
</IconButton>
|
||||
}
|
||||
buildMenuTemplate={() => [
|
||||
{
|
||||
label: 'Delete',
|
||||
click: () => this._removeParameter(i),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Column>
|
||||
</Line>
|
||||
</div>
|
||||
</MiniToolbar>
|
||||
<Line expand noMargin>
|
||||
<Column expand>
|
||||
<SelectField
|
||||
floatingLabelText="Type"
|
||||
value={parameter.getType()}
|
||||
onChange={(e, i, value) => {
|
||||
parameter.setType(value);
|
||||
this.forceUpdate();
|
||||
this.props.onParametersUpdated();
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<MenuItem value="objectList" primaryText="Objects" />
|
||||
<MenuItem value="expression" primaryText="Number" />
|
||||
<MenuItem
|
||||
value="string"
|
||||
primaryText="String (text)"
|
||||
/>
|
||||
<MenuItem
|
||||
value="key"
|
||||
primaryText="Keyboard Key (text)"
|
||||
/>
|
||||
<MenuItem
|
||||
value="mouse"
|
||||
primaryText="Mouse button (text)"
|
||||
/>
|
||||
</SelectField>
|
||||
</Column>
|
||||
{parameter.getType() === 'objectList' && (
|
||||
<Column expand>
|
||||
<SelectField
|
||||
floatingLabelText="Object type"
|
||||
floatingLabelFixed
|
||||
value={parameter.getExtraInfo()}
|
||||
onChange={(e, i, value) => {
|
||||
parameter.setExtraInfo(value);
|
||||
this.forceUpdate();
|
||||
this.props.onParametersUpdated();
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<MenuItem value="" primaryText="Any object" />
|
||||
{objectMetadata.map(
|
||||
(metadata: EnumeratedObjectMetadata) => {
|
||||
if (metadata.name === '') {
|
||||
// Base object is an "abstract" object
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
key={metadata.name}
|
||||
value={metadata.name}
|
||||
primaryText={metadata.fullName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</SelectField>
|
||||
</Column>
|
||||
)}
|
||||
</Line>
|
||||
<Line expand noMargin>
|
||||
<Column expand>
|
||||
<TextField
|
||||
floatingLabelText="Description"
|
||||
value={parameter.getDescription()}
|
||||
onChange={(e, text) => {
|
||||
parameter.setDescription(text);
|
||||
this.forceUpdate();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
</Column>
|
||||
</Line>
|
||||
</React.Fragment>
|
||||
)
|
||||
)}
|
||||
</ThemeConsumer>
|
||||
{parameters.size() === 0 ? (
|
||||
<EmptyMessage>No parameters for this function.</EmptyMessage>
|
||||
) : null}
|
||||
<Line justifyContent="space-between">
|
||||
<Column>
|
||||
<HelpButton helpPagePath="/events/functions" />
|
||||
</Column>
|
||||
<Column>
|
||||
<FlatButton
|
||||
label="Add a parameter"
|
||||
onClick={this._addParameter}
|
||||
/>
|
||||
</Column>
|
||||
</Line>
|
||||
</div>
|
||||
</Line>
|
||||
</div>
|
||||
</Column>
|
||||
|
@@ -176,6 +176,7 @@ export default class EventsFunctionsExtensionEditor extends React.Component<
|
||||
this._globalObjectsContainer &&
|
||||
this._objectsContainer ? (
|
||||
<EventsSheet
|
||||
key={selectedEventsFunction.ptr}
|
||||
ref={editor => (this.editor = editor)}
|
||||
project={project}
|
||||
layout={null}
|
||||
|
@@ -2,18 +2,6 @@
|
||||
|
||||
exports[`EnumerateInstructions can create the tree of instructions 1`] = `
|
||||
Object {
|
||||
"AdMob banners and interstitial screens": Object {
|
||||
"Banner is displayed": Object {
|
||||
"displayedName": "Banner is displayed",
|
||||
"fullGroupName": "AdMob banners and interstitial screens/",
|
||||
"type": "AdMobObject::BannerDisplayed",
|
||||
},
|
||||
"Interstitial screen is ready": Object {
|
||||
"displayedName": "Interstitial screen is ready",
|
||||
"fullGroupName": "AdMob banners and interstitial screens/",
|
||||
"type": "AdMobObject::InterstitialReady",
|
||||
},
|
||||
},
|
||||
"Advanced": Object {
|
||||
"And": Object {
|
||||
"displayedName": "And",
|
||||
@@ -2376,26 +2364,6 @@ Array [
|
||||
"fullGroupName": "Physics behavior/Movement",
|
||||
"type": "PhysicsBehavior::SetStatic",
|
||||
},
|
||||
Object {
|
||||
"displayedName": "Hide banner ad",
|
||||
"fullGroupName": "AdMob banners and interstitial screens/Banner",
|
||||
"type": "AdMobObject::HideBanner",
|
||||
},
|
||||
Object {
|
||||
"displayedName": "Preload interstitial screen",
|
||||
"fullGroupName": "AdMob banners and interstitial screens/Interstitial screen",
|
||||
"type": "AdMobObject::PreloadInterstitial",
|
||||
},
|
||||
Object {
|
||||
"displayedName": "Show banner ad",
|
||||
"fullGroupName": "AdMob banners and interstitial screens/Banner",
|
||||
"type": "AdMobObject::ShowBanner",
|
||||
},
|
||||
Object {
|
||||
"displayedName": "Show interstitial screen",
|
||||
"fullGroupName": "AdMob banners and interstitial screens/Interstitial screen",
|
||||
"type": "AdMobObject::ShowInterstitial",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
@@ -3346,15 +3314,5 @@ Array [
|
||||
"fullGroupName": "Physics behavior/Displacement",
|
||||
"type": "PhysicsBehavior::LinearVelocityY",
|
||||
},
|
||||
Object {
|
||||
"displayedName": "Banner is displayed",
|
||||
"fullGroupName": "AdMob banners and interstitial screens/",
|
||||
"type": "AdMobObject::BannerDisplayed",
|
||||
},
|
||||
Object {
|
||||
"displayedName": "Interstitial screen is ready",
|
||||
"fullGroupName": "AdMob banners and interstitial screens/",
|
||||
"type": "AdMobObject::InterstitialReady",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
@@ -70,7 +70,7 @@ export default class InstructionParametersEditor extends React.Component<
|
||||
}, 300); // Let the time to the dialog that is potentially containing the InstructionParametersEditor to finish its transition.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
focus() {
|
||||
// Verify that there is a field to focus.
|
||||
if (
|
||||
|
@@ -104,7 +104,7 @@ export default class InstancePropertiesEditor extends Component {
|
||||
_renderEmpty() {
|
||||
return (
|
||||
<EmptyMessage>
|
||||
Click on an instance on the scene to display its properties
|
||||
Click on an instance in the scene to display its properties
|
||||
</EmptyMessage>
|
||||
);
|
||||
}
|
||||
|
@@ -39,11 +39,11 @@ export default class ViewPosition {
|
||||
var viewRotation = 0;
|
||||
var tmp = x;
|
||||
x =
|
||||
Math.cos(viewRotation / 180 * 3.14159) * x -
|
||||
Math.sin(viewRotation / 180 * 3.14159) * y;
|
||||
Math.cos(viewRotation / 180 * Math.PI) * x -
|
||||
Math.sin(viewRotation / 180 * Math.PI) * y;
|
||||
y =
|
||||
Math.sin(viewRotation / 180 * 3.14159) * tmp +
|
||||
Math.cos(viewRotation / 180 * 3.14159) * y;
|
||||
Math.sin(viewRotation / 180 * Math.PI) * tmp +
|
||||
Math.cos(viewRotation / 180 * Math.PI) * y;
|
||||
|
||||
return [x + this.viewX, y + this.viewY];
|
||||
};
|
||||
@@ -59,11 +59,11 @@ export default class ViewPosition {
|
||||
var viewRotation = -0;
|
||||
var tmp = x;
|
||||
x =
|
||||
Math.cos(viewRotation / 180 * 3.14159) * x -
|
||||
Math.sin(viewRotation / 180 * 3.14159) * y;
|
||||
Math.cos(viewRotation / 180 * Math.PI) * x -
|
||||
Math.sin(viewRotation / 180 * Math.PI) * y;
|
||||
y =
|
||||
Math.sin(viewRotation / 180 * 3.14159) * tmp +
|
||||
Math.cos(viewRotation / 180 * 3.14159) * y;
|
||||
Math.sin(viewRotation / 180 * Math.PI) * tmp +
|
||||
Math.cos(viewRotation / 180 * Math.PI) * y;
|
||||
|
||||
x *= Math.abs(this._pixiContainer.scale.x);
|
||||
y *= Math.abs(this._pixiContainer.scale.y);
|
||||
|
@@ -1,27 +0,0 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { type EditorProps } from './EditorProps.flow';
|
||||
import { Line, Column } from '../../UI/Grid';
|
||||
import PropertiesEditor from '../../PropertiesEditor';
|
||||
import propertiesMapToSchema from '../../PropertiesEditor/PropertiesMapToSchema';
|
||||
|
||||
export default class AdMobEditor extends React.Component<EditorProps, void> {
|
||||
render() {
|
||||
const { object, project } = this.props;
|
||||
|
||||
const properties = object.getProperties(project);
|
||||
const propertiesSchema = propertiesMapToSchema(
|
||||
properties,
|
||||
object => object.getProperties(project),
|
||||
(object, name, value) => object.updateProperty(name, value, project)
|
||||
);
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<Line>
|
||||
<PropertiesEditor schema={propertiesSchema} instances={[object]} />
|
||||
</Line>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
}
|
@@ -4,7 +4,7 @@ import Checkbox from 'material-ui/Checkbox';
|
||||
import TextField from 'material-ui/TextField';
|
||||
import { Line, Column } from '../../UI/Grid';
|
||||
import ColorPicker from '../../UI/ColorField/ColorPicker';
|
||||
import MiniToolbar from '../../UI/MiniToolbar';
|
||||
import MiniToolbar, { MiniToolbarText } from '../../UI/MiniToolbar';
|
||||
import { type EditorProps } from './EditorProps.flow';
|
||||
const gd = global.gd;
|
||||
|
||||
@@ -18,9 +18,6 @@ const styles = {
|
||||
...toolbarItemStyle,
|
||||
},
|
||||
toolbarItem: toolbarItemStyle,
|
||||
toolbarText: {
|
||||
marginRight: 5,
|
||||
},
|
||||
checkbox: {
|
||||
width: 'auto',
|
||||
...toolbarItemStyle,
|
||||
@@ -35,7 +32,7 @@ export default class TextEditor extends React.Component<EditorProps, void> {
|
||||
return (
|
||||
<Column noMargin>
|
||||
<MiniToolbar>
|
||||
<p style={styles.toolbarText}>Size:</p>
|
||||
<MiniToolbarText>Size:</MiniToolbarText>
|
||||
<TextField
|
||||
type="number"
|
||||
style={styles.sizeTextField}
|
||||
@@ -45,7 +42,7 @@ export default class TextEditor extends React.Component<EditorProps, void> {
|
||||
this.forceUpdate();
|
||||
}}
|
||||
/>
|
||||
<p style={styles.toolbarText}>Color:</p>
|
||||
<MiniToolbarText>Color:</MiniToolbarText>
|
||||
<ColorPicker
|
||||
style={styles.sizeTextField}
|
||||
disableAlpha
|
||||
|
@@ -4,7 +4,6 @@ import PanelSpriteEditor from './Editors/PanelSpriteEditor';
|
||||
import SpriteEditor from './Editors/SpriteEditor';
|
||||
import EmptyEditor from './Editors/EmptyEditor';
|
||||
import ShapePainterEditor from './Editors/ShapePainterEditor';
|
||||
import AdMobEditor from './Editors/AdMobEditor';
|
||||
import ParticleEmitterEditor from './Editors/ParticleEmitterEditor';
|
||||
const gd = global.gd;
|
||||
|
||||
@@ -68,11 +67,6 @@ export default {
|
||||
newObjectCreator: () => new gd.PanelSpriteObject(''),
|
||||
castToObjectType: object => gd.asPanelSpriteObject(object),
|
||||
},
|
||||
'AdMobObject::AdMob': {
|
||||
component: AdMobEditor,
|
||||
newObjectCreator: () => new gd.AdMobObject(''),
|
||||
castToObjectType: object => gd.asAdMobObject(object),
|
||||
},
|
||||
'TextObject::Text': {
|
||||
component: TextEditor,
|
||||
newObjectCreator: () => new gd.TextObject(''),
|
||||
|
@@ -2,7 +2,6 @@ import RenderedUnknownInstance from './Renderers/RenderedUnknownInstance';
|
||||
import RenderedSpriteInstance from './Renderers/RenderedSpriteInstance';
|
||||
import RenderedTiledSpriteInstance from './Renderers/RenderedTiledSpriteInstance';
|
||||
import RenderedPanelSpriteInstance from './Renderers/RenderedPanelSpriteInstance';
|
||||
import RenderedAdMobInstance from './Renderers/RenderedAdMobInstance';
|
||||
import RenderedTextInstance from './Renderers/RenderedTextInstance';
|
||||
import RenderedShapePainterInstance from './Renderers/RenderedShapePainterInstance';
|
||||
import RenderedTextEntryInstance from './Renderers/RenderedTextEntryInstance';
|
||||
@@ -20,7 +19,6 @@ export default {
|
||||
Sprite: RenderedSpriteInstance,
|
||||
'TiledSpriteObject::TiledSprite': RenderedTiledSpriteInstance,
|
||||
'PanelSpriteObject::PanelSprite': RenderedPanelSpriteInstance,
|
||||
'AdMobObject::AdMob': RenderedAdMobInstance,
|
||||
'TextObject::Text': RenderedTextInstance,
|
||||
'PrimitiveDrawing::Drawer': RenderedShapePainterInstance,
|
||||
'TextEntryObject::TextEntry': RenderedTextEntryInstance,
|
||||
|
@@ -1,91 +0,0 @@
|
||||
import RenderedInstance from './RenderedInstance';
|
||||
import PIXI from 'pixi.js';
|
||||
|
||||
/**
|
||||
* Renderer for an AdMob object.
|
||||
*
|
||||
* @extends RenderedInstance
|
||||
* @class RenderedAdMobInstance
|
||||
* @constructor
|
||||
*/
|
||||
function RenderedAdMobInstance(
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
) {
|
||||
RenderedInstance.call(
|
||||
this,
|
||||
project,
|
||||
layout,
|
||||
instance,
|
||||
associatedObject,
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
);
|
||||
|
||||
//Setup the PIXI object:
|
||||
this._pixiObject = new PIXI.Container();
|
||||
this._pixiContainer.addChild(this._pixiObject);
|
||||
|
||||
this._titleText = new PIXI.Text('Ad banner object');
|
||||
this._titleText.style = {
|
||||
fill: 'white',
|
||||
font: 'bold 18px Arial',
|
||||
};
|
||||
this._titleText.position.x =
|
||||
this.getDefaultWidth() / 2 - this._titleText.width / 2;
|
||||
|
||||
this._text = new PIXI.Text(
|
||||
'displayed on Android at the top or bottom of the screen'
|
||||
);
|
||||
this._text.style = {
|
||||
fill: 'white',
|
||||
font: 'italic 14px Arial',
|
||||
};
|
||||
this._text.position.x = this.getDefaultWidth() / 2 - this._text.width / 2;
|
||||
this._text.position.y = 30;
|
||||
|
||||
this._placeholder = new PIXI.Graphics();
|
||||
this._placeholder.beginFill(0x15b4f9);
|
||||
this._placeholder.lineStyle(1, 0x12286f, 1);
|
||||
this._placeholder.moveTo(0, 0);
|
||||
this._placeholder.lineTo(this.getDefaultWidth(), 0);
|
||||
this._placeholder.lineTo(this.getDefaultWidth(), this.getDefaultHeight());
|
||||
this._placeholder.lineTo(0, this.getDefaultHeight());
|
||||
this._placeholder.lineTo(0, 0);
|
||||
this._placeholder.endFill();
|
||||
|
||||
this._pixiObject.addChild(this._placeholder);
|
||||
this._pixiObject.addChild(this._text);
|
||||
this._pixiObject.addChild(this._titleText);
|
||||
}
|
||||
RenderedAdMobInstance.prototype = Object.create(RenderedInstance.prototype);
|
||||
|
||||
/**
|
||||
* Return a URL for thumbnail of the specified object.
|
||||
*/
|
||||
RenderedAdMobInstance.getThumbnail = function(
|
||||
project,
|
||||
resourcesLoader,
|
||||
object
|
||||
) {
|
||||
return 'JsPlatform/Extensions/admobicon24.png';
|
||||
};
|
||||
|
||||
RenderedAdMobInstance.prototype.update = function() {
|
||||
this._pixiObject.position.x = this._instance.getX();
|
||||
this._pixiObject.position.y = this._instance.getY();
|
||||
};
|
||||
|
||||
RenderedAdMobInstance.prototype.getDefaultWidth = function() {
|
||||
return 400;
|
||||
};
|
||||
|
||||
RenderedAdMobInstance.prototype.getDefaultHeight = function() {
|
||||
return 64;
|
||||
};
|
||||
|
||||
export default RenderedAdMobInstance;
|
@@ -23,10 +23,10 @@ export default ({ profile }: Props) =>
|
||||
<Column>
|
||||
<Line alignItems="center">
|
||||
<Avatar src={getGravatarUrl(profile.email || '', { size: 40 })} />
|
||||
<span style={styles.title}>You are connect as {profile.email}</span>
|
||||
<span style={styles.title}>You are connected as {profile.email}</span>
|
||||
</Line>
|
||||
<Line>
|
||||
<p>With your account, you can access to GDevelop online services.</p>
|
||||
<p>An account allows you to access GDevelop services online.</p>
|
||||
</Line>
|
||||
</Column>
|
||||
) : (
|
||||
|