Files
GDevelop/Core/tests/DummyPlatform.cpp
T
D8H d40e360b8a Add support for behaviors based on other behaviors ("behavior composition") (#2781)
* This allows [custom behaviors](http://wiki.compilgames.net/doku.php/gdevelop5/behaviors/events-based-behaviors), that you can create in your project or get from extensions, to require the presence of one or multiple other behaviors on an object.
  * This is an advanced feature that is helpful to create behaviors that are based on other. For example, a behavior "Platformer enemy" using the "Platformer object" behavior and adding specific actions, conditions and logic to make an enemy chase the player.
  * If you create a behavior and want to use this, just go to the properties of this behavior and add a new property. Choose the type "Required Behavior" for this property. You can then use this new behavior in the events of the behavior you just edited.
* To use a behavior based on another, you don't need to do anything special! Just add it to your object as usual: any missing behavior will be added to your object, so you can start using it immediately.
2021-09-06 19:51:42 +01:00

302 lines
12 KiB
C++

/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Tools/Localization.h"
#include "catch.hpp"
class BehaviorWithRequiredBehaviorProperty : public gd::Behavior {
public:
BehaviorWithRequiredBehaviorProperty() {};
virtual ~BehaviorWithRequiredBehaviorProperty(){};
virtual Behavior* Clone() const override {
return new BehaviorWithRequiredBehaviorProperty(*this);
}
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
const gd::SerializerElement& behaviorContent) const override {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties["requiredBehaviorProperty"]
.SetLabel("A required behavior")
.SetValue(behaviorContent.GetStringAttribute("requiredBehaviorProperty"))
.SetType("Behavior")
.AddExtraInfo("MyExtension::MyBehavior");
return properties;
}
virtual bool UpdateProperty(gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value) override {
if (name == _("requiredBehaviorProperty")) {
behaviorContent.SetAttribute("requiredBehaviorProperty", value);
return true;
}
return false;
}
virtual void InitializeContent(
gd::SerializerElement& behaviorContent) override {
behaviorContent.SetAttribute("requiredBehaviorProperty", "");
}
};
class BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior
: public gd::Behavior {
public:
BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior() {};
virtual ~BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior(){};
virtual Behavior* Clone() const override {
return new BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior(
*this);
}
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
const gd::SerializerElement& behaviorContent) const override {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties["requiredBehaviorProperty"]
.SetLabel("A required behavior")
.SetValue(behaviorContent.GetStringAttribute("requiredBehaviorProperty"))
.SetType("Behavior")
.AddExtraInfo("MyExtension::BehaviorWithRequiredBehaviorProperty");
return properties;
}
virtual bool UpdateProperty(gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value) override {
if (name == _("requiredBehaviorProperty")) {
behaviorContent.SetAttribute("requiredBehaviorProperty", value);
return true;
}
return false;
}
virtual void InitializeContent(
gd::SerializerElement& behaviorContent) override {
behaviorContent.SetAttribute("requiredBehaviorProperty", "");
}
};
void SetupProjectWithDummyPlatform(gd::Project& project,
gd::Platform& platform) {
// Don't show extension loading logs for tests (too verbose).
platform.EnableExtensionLoadingLogs(false);
std::shared_ptr<gd::PlatformExtension> baseObjectExtension =
std::shared_ptr<gd::PlatformExtension>(new gd::PlatformExtension);
baseObjectExtension->SetExtensionInformation(
"BuiltinObject", "Base Object dummy extension", "", "", "");
auto baseObject = baseObjectExtension->AddObject<gd::Object>(
"", "Dummy Base Object", "Dummy Base Object", "");
std::shared_ptr<gd::PlatformExtension> extension =
std::shared_ptr<gd::PlatformExtension>(new gd::PlatformExtension);
extension->SetExtensionInformation(
"MyExtension", "My testing extension", "", "", "");
extension
->AddAction("DoSomething",
"Do something",
"This does something",
"Do something please",
"",
"",
"")
.AddParameter("expression", "Parameter 1 (a number)")
.SetFunctionName("doSomething");
extension->AddExpression("GetNumber", "Get me a number", "", "", "")
.SetFunctionName("getNumber");
extension
->AddExpression(
"GetVariableAsNumber", "Get me a variable value", "", "", "")
.AddParameter("scenevar", "Scene variable")
.SetFunctionName("returnVariable");
extension->AddStrExpression("ToString", "ToString", "", "", "")
.AddParameter("expression", "Number to convert to string")
.SetFunctionName("toString");
extension
->AddExpression("MouseX",
_("Cursor X position"),
_("Cursor X position"),
_("Mouse cursor"),
"res/actions/mouse.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("camera", _("Camera"), "", true)
.SetDefaultValue("0")
.SetFunctionName("getMouseX");
extension
->AddExpression("GetGlobalVariableAsNumber",
"Get me a global variable value",
"",
"",
"")
.AddParameter("globalvar", "Global variable")
.SetFunctionName("returnVariable");
extension
->AddExpression(
"GetNumberWith2Params", "Get me a number with 2 params", "", "", "")
.AddParameter("expression", "")
.AddParameter("string", "")
.SetFunctionName("getNumberWith2Params");
extension
->AddExpression("GetNumberWith3Params",
"Get me a number with 3 params, 1 optional",
"",
"",
"")
.AddParameter("expression", "")
.AddParameter("string", "")
.AddParameter("expression", "", "", true)
.SetFunctionName("getNumberWith3Params");
extension
->AddStrExpression(
"GetStringWith2ObjectParamAnd2ObjectVarParam",
"Get string with twice an object param and an objectvar param",
"",
"",
"")
.AddParameter("object", _("Object 1 parameter"))
.AddParameter("objectvar", _("Variable for object 1"))
.AddParameter("object", _("Object 2 parameter"))
.AddParameter("objectvar", _("Variable for object 2"))
.SetFunctionName("getStringWith2ObjectParamAnd2ObjectVarParam");
auto& object = extension->AddObject<gd::Object>(
"Sprite", "Dummy Sprite", "Dummy sprite object", "");
object
.AddExpression("GetObjectVariableAsNumber",
"Get an object variable value",
"",
"",
"")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectvar", _("Variable"))
.SetFunctionName("returnVariable");
object.AddExpression("GetObjectNumber", "Get number from object", "", "", "")
.AddParameter("object", _("Object"), "Sprite")
.SetFunctionName("getObjectNumber");
object
.AddStrExpression("GetObjectStringWith1Param",
"Get string from object with 1 param",
"",
"",
"")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("expression", _("Number parameter"))
.SetFunctionName("getObjectStringWith1Param");
object
.AddStrExpression("GetObjectStringWith3Param",
"Get string from object with 3 param",
"",
"",
"")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("expression", _("Number parameter"))
.AddParameter("string", _("String parameter"))
.AddParameter("", _("Identifier parameter"))
.SetFunctionName("getObjectStringWith3Param");
object
.AddStrExpression("GetObjectStringWith2ObjectParam",
"Get string from object with a 2 objects param",
"",
"",
"")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("object", _("Object parameter"))
.AddParameter("objectPtr", _("Object parameter"))
.SetFunctionName("getObjectStringWith2ObjectParam");
{
auto& behavior =
extension->AddBehavior("MyBehavior",
"Dummy behavior",
"MyBehavior",
"A dummy behavior for tests",
"",
"",
"",
gd::make_unique<gd::Behavior>(),
gd::make_unique<gd::BehaviorsSharedData>());
behavior
.AddAction("BehaviorDoSomething",
"Do something on behavior",
"This does something with the behavior",
"Do something with the behavior please",
"",
"",
"")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "MyExtension::MyBehavior")
.AddParameter("expression", "Parameter 1 (a number)")
.SetFunctionName("behaviorDoSomething");
behavior
.AddStrExpression("GetBehaviorStringWith1Param",
"Get string from behavior with 1 param",
"",
"",
"")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "MyExtension::MyBehavior")
.AddParameter("expression", _("Number parameter"))
.SetFunctionName("getBehaviorStringWith1Param");
behavior
.AddExpression("GetBehaviorNumberWith1Param",
"Get number from behavior with 1 param",
"",
"",
"")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "MyExtension::MyBehavior")
.AddParameter("expression", _("Number parameter"))
.SetFunctionName("getBehaviorNumberWith1Param");
}
{
auto& behavior =
extension->AddBehavior("MyOtherBehavior",
"Another Dummy behavior",
"MyOtherBehavior",
"Another dummy behavior for tests",
"",
"",
"",
gd::make_unique<gd::Behavior>(),
gd::make_unique<gd::BehaviorsSharedData>());
}
{
auto& behavior = extension->AddBehavior(
"BehaviorWithRequiredBehaviorProperty",
"BehaviorWithRequiredBehaviorProperty",
"BehaviorWithRequiredBehaviorProperty",
"A dummy behavior requiring another behavior (MyBehavior)",
"",
"",
"",
gd::make_unique<BehaviorWithRequiredBehaviorProperty>(),
gd::make_unique<gd::BehaviorsSharedData>());
}
{
auto& behavior = extension->AddBehavior(
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior",
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior",
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior",
"A dummy behavior requiring another behavior "
"(BehaviorWithRequiredBehaviorProperty) that itself requires another "
"behavior (MyBehavior)",
"",
"",
"",
gd::make_unique<
BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior>(),
gd::make_unique<gd::BehaviorsSharedData>());
}
platform.AddExtension(baseObjectExtension);
platform.AddExtension(extension);
project.AddPlatform(platform);
}