From 7396c0b4cef54f0d3cff7cf22e496cc6efa34fd3 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:05:46 +0200 Subject: [PATCH 1/3] Add touchingColor() with mask param to target handlers --- include/scratchcpp/ispritehandler.h | 3 +++ include/scratchcpp/istagehandler.h | 3 +++ test/mocks/spritehandlermock.h | 1 + test/mocks/stagehandlermock.h | 1 + 4 files changed, 8 insertions(+) diff --git a/include/scratchcpp/ispritehandler.h b/include/scratchcpp/ispritehandler.h index 9bfb4307..af760ce4 100644 --- a/include/scratchcpp/ispritehandler.h +++ b/include/scratchcpp/ispritehandler.h @@ -92,6 +92,9 @@ class LIBSCRATCHCPP_EXPORT ISpriteHandler /*! Used to check whether the sprite touches the given color. */ virtual bool touchingColor(const Value &color) const = 0; + + /*! Used to check whether the mask part of the sprite touches the given color. */ + virtual bool touchingColor(const Value &color, const Value &mask) const = 0; }; } // namespace libscratchcpp diff --git a/include/scratchcpp/istagehandler.h b/include/scratchcpp/istagehandler.h index 0b397e17..6b51ce26 100644 --- a/include/scratchcpp/istagehandler.h +++ b/include/scratchcpp/istagehandler.h @@ -69,6 +69,9 @@ class LIBSCRATCHCPP_EXPORT IStageHandler /*! Used to check whether the stage touches the given color. */ virtual bool touchingColor(const Value &color) const = 0; + + /*! Used to check whether the mask part of the stage touches the given color. */ + virtual bool touchingColor(const Value &color, const Value &mask) const = 0; }; } // namespace libscratchcpp diff --git a/test/mocks/spritehandlermock.h b/test/mocks/spritehandlermock.h index d944f807..ef4c61c4 100644 --- a/test/mocks/spritehandlermock.h +++ b/test/mocks/spritehandlermock.h @@ -38,4 +38,5 @@ class SpriteHandlerMock : public ISpriteHandler MOCK_METHOD(bool, touchingClones, (const std::vector &), (const, override)); MOCK_METHOD(bool, touchingPoint, (double, double), (const, override)); MOCK_METHOD(bool, touchingColor, (const Value &), (const, override)); + MOCK_METHOD(bool, touchingColor, (const Value &, const Value &), (const, override)); }; diff --git a/test/mocks/stagehandlermock.h b/test/mocks/stagehandlermock.h index a7e15055..4702328d 100644 --- a/test/mocks/stagehandlermock.h +++ b/test/mocks/stagehandlermock.h @@ -29,4 +29,5 @@ class StageHandlerMock : public IStageHandler MOCK_METHOD(bool, touchingClones, (const std::vector &), (const, override)); MOCK_METHOD(bool, touchingPoint, (double, double), (const, override)); MOCK_METHOD(bool, touchingColor, (const Value &), (const, override)); + MOCK_METHOD(bool, touchingColor, (const Value &, const Value &), (const, override)); }; From 1a412326ac881da735cef88907e0f0fd4e78fe20 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:23:41 +0200 Subject: [PATCH 2/3] Add touchingColor() with mask param to Target --- include/scratchcpp/sprite.h | 1 + include/scratchcpp/stage.h | 1 + include/scratchcpp/target.h | 1 + src/scratch/sprite.cpp | 9 +++++++++ src/scratch/stage.cpp | 9 +++++++++ src/scratch/target.cpp | 6 ++++++ test/mocks/targetmock.h | 1 + test/scratch_classes/sprite_test.cpp | 7 +++++++ test/scratch_classes/stage_test.cpp | 7 +++++++ test/scratch_classes/target_test.cpp | 1 + 10 files changed, 43 insertions(+) diff --git a/include/scratchcpp/sprite.h b/include/scratchcpp/sprite.h index 328c6371..af6ec39a 100644 --- a/include/scratchcpp/sprite.h +++ b/include/scratchcpp/sprite.h @@ -82,6 +82,7 @@ class LIBSCRATCHCPP_EXPORT Sprite bool touchingPoint(double x, double y) const override; bool touchingColor(const Value &color) const override; + bool touchingColor(const Value &color, const Value &mask) const override; void setGraphicsEffectValue(IGraphicsEffect *effect, double value) override; diff --git a/include/scratchcpp/stage.h b/include/scratchcpp/stage.h index 0d37c862..39d969bd 100644 --- a/include/scratchcpp/stage.h +++ b/include/scratchcpp/stage.h @@ -56,6 +56,7 @@ class LIBSCRATCHCPP_EXPORT Stage : public Target bool touchingPoint(double x, double y) const override; bool touchingColor(const Value &color) const override; + bool touchingColor(const Value &color, const Value &mask) const override; void setGraphicsEffectValue(IGraphicsEffect *effect, double value) override; diff --git a/include/scratchcpp/target.h b/include/scratchcpp/target.h index cb8f7c1b..82a92eec 100644 --- a/include/scratchcpp/target.h +++ b/include/scratchcpp/target.h @@ -101,6 +101,7 @@ class LIBSCRATCHCPP_EXPORT Target virtual bool touchingPoint(double x, double y) const; bool touchingEdge() const; virtual bool touchingColor(const Value &color) const; + virtual bool touchingColor(const Value &color, const Value &mask) const; double graphicsEffectValue(IGraphicsEffect *effect) const; virtual void setGraphicsEffectValue(IGraphicsEffect *effect, double value); diff --git a/src/scratch/sprite.cpp b/src/scratch/sprite.cpp index d711ca7c..42d67557 100644 --- a/src/scratch/sprite.cpp +++ b/src/scratch/sprite.cpp @@ -503,6 +503,15 @@ bool Sprite::touchingColor(const Value &color) const return impl->iface->touchingColor(color); } +/*! Overrides Target#touchingColor(). */ +bool Sprite::touchingColor(const Value &color, const Value &mask) const +{ + if (!impl->iface) + return false; + + return impl->iface->touchingColor(color, mask); +} + /*! Overrides Target#setGraphicsEffectValue(). */ void Sprite::setGraphicsEffectValue(IGraphicsEffect *effect, double value) { diff --git a/src/scratch/stage.cpp b/src/scratch/stage.cpp index d798451e..ac312ffa 100644 --- a/src/scratch/stage.cpp +++ b/src/scratch/stage.cpp @@ -185,6 +185,15 @@ bool Stage::touchingColor(const Value &color) const return impl->iface->touchingColor(color); } +/*! Overrides Target#touchingColor(). */ +bool Stage::touchingColor(const Value &color, const Value &mask) const +{ + if (!impl->iface) + return false; + + return impl->iface->touchingColor(color, mask); +} + /*! Overrides Target#setGraphicsEffectValue(). */ void Stage::setGraphicsEffectValue(IGraphicsEffect *effect, double value) { diff --git a/src/scratch/target.cpp b/src/scratch/target.cpp index 1e9f4b46..b1027233 100644 --- a/src/scratch/target.cpp +++ b/src/scratch/target.cpp @@ -520,6 +520,12 @@ bool Target::touchingColor(const Value &color) const return false; } +/*! Returns true if the mask part of the Target is touching the given color (RGB triplet). */ +bool Target::touchingColor(const Value &color, const Value &mask) const +{ + return false; +} + /*! Returns the value of the given graphics effect. */ double Target::graphicsEffectValue(IGraphicsEffect *effect) const { diff --git a/test/mocks/targetmock.h b/test/mocks/targetmock.h index 5df18e09..20f3bd7a 100644 --- a/test/mocks/targetmock.h +++ b/test/mocks/targetmock.h @@ -28,6 +28,7 @@ class TargetMock : public Target MOCK_METHOD(bool, touchingPoint, (double, double), (const, override)); MOCK_METHOD(bool, touchingColor, (const Value &), (const, override)); + MOCK_METHOD(bool, touchingColor, (const Value &, const Value &), (const, override)); MOCK_METHOD(void, setGraphicsEffectValue, (IGraphicsEffect *, double), (override)); MOCK_METHOD(void, clearGraphicsEffects, (), (override)); diff --git a/test/scratch_classes/sprite_test.cpp b/test/scratch_classes/sprite_test.cpp index ea79c577..9c00e4d7 100644 --- a/test/scratch_classes/sprite_test.cpp +++ b/test/scratch_classes/sprite_test.cpp @@ -825,6 +825,7 @@ TEST(SpriteTest, TouchingColor) { Sprite sprite; ASSERT_FALSE(sprite.touchingColor(0)); + ASSERT_FALSE(sprite.touchingColor(0, 0)); SpriteHandlerMock iface; EXPECT_CALL(iface, init); @@ -836,6 +837,12 @@ TEST(SpriteTest, TouchingColor) EXPECT_CALL(iface, touchingColor(v2)).WillOnce(Return(true)); ASSERT_TRUE(sprite.touchingColor(v2)); + + EXPECT_CALL(iface, touchingColor(v1, v2)).WillOnce(Return(false)); + ASSERT_FALSE(sprite.touchingColor(v1, v2)); + + EXPECT_CALL(iface, touchingColor(v2, v1)).WillOnce(Return(true)); + ASSERT_TRUE(sprite.touchingColor(v2, v1)); } TEST(SpriteTest, GraphicsEffects) diff --git a/test/scratch_classes/stage_test.cpp b/test/scratch_classes/stage_test.cpp index 78d3763b..ee69c187 100644 --- a/test/scratch_classes/stage_test.cpp +++ b/test/scratch_classes/stage_test.cpp @@ -222,6 +222,7 @@ TEST(SpriteTest, TouchingColor) { Stage stage; ASSERT_FALSE(stage.touchingColor(0)); + ASSERT_FALSE(stage.touchingColor(0, 0)); StageHandlerMock iface; EXPECT_CALL(iface, init); @@ -233,6 +234,12 @@ TEST(SpriteTest, TouchingColor) EXPECT_CALL(iface, touchingColor(v2)).WillOnce(Return(true)); ASSERT_TRUE(stage.touchingColor(v2)); + + EXPECT_CALL(iface, touchingColor(v1, v2)).WillOnce(Return(false)); + ASSERT_FALSE(stage.touchingColor(v1, v2)); + + EXPECT_CALL(iface, touchingColor(v2, v1)).WillOnce(Return(true)); + ASSERT_TRUE(stage.touchingColor(v2, v1)); } TEST(StageTest, GraphicsEffects) diff --git a/test/scratch_classes/target_test.cpp b/test/scratch_classes/target_test.cpp index e71771d2..edf559a2 100644 --- a/test/scratch_classes/target_test.cpp +++ b/test/scratch_classes/target_test.cpp @@ -716,6 +716,7 @@ TEST(TargetTest, TouchingColor) Target target; Value v; ASSERT_FALSE(target.touchingColor(v)); + ASSERT_FALSE(target.touchingColor(v, v)); } TEST(TargetTest, GraphicsEffects) From 4d57b321110744e2d7c1402c224b065b1d7cd9e1 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:59:46 +0200 Subject: [PATCH 3/3] Implement sensing_coloristouchingcolor block --- src/blocks/sensingblocks.cpp | 15 ++++++ src/blocks/sensingblocks.h | 4 ++ test/blocks/sensing_blocks_test.cpp | 75 +++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/src/blocks/sensingblocks.cpp b/src/blocks/sensingblocks.cpp index fee64bc0..0a198a97 100644 --- a/src/blocks/sensingblocks.cpp +++ b/src/blocks/sensingblocks.cpp @@ -32,6 +32,7 @@ void SensingBlocks::registerBlocks(IEngine *engine) // Blocks engine->addCompileFunction(this, "sensing_touchingobject", &compileTouchingObject); engine->addCompileFunction(this, "sensing_touchingcolor", &compileTouchingColor); + engine->addCompileFunction(this, "sensing_coloristouchingcolor", &compileColorIsTouchingColor); engine->addCompileFunction(this, "sensing_distanceto", &compileDistanceTo); engine->addCompileFunction(this, "sensing_askandwait", &compileAskAndWait); engine->addCompileFunction(this, "sensing_answer", &compileAnswer); @@ -60,6 +61,7 @@ void SensingBlocks::registerBlocks(IEngine *engine) // Inputs engine->addInput(this, "TOUCHINGOBJECTMENU", TOUCHINGOBJECTMENU); engine->addInput(this, "COLOR", COLOR); + engine->addInput(this, "COLOR2", COLOR2); engine->addInput(this, "DISTANCETOMENU", DISTANCETOMENU); engine->addInput(this, "QUESTION", QUESTION); engine->addInput(this, "KEY_OPTION", KEY_OPTION); @@ -139,6 +141,13 @@ void SensingBlocks::compileTouchingColor(Compiler *compiler) compiler->addFunctionCall(&touchingColor); } +void SensingBlocks::compileColorIsTouchingColor(Compiler *compiler) +{ + compiler->addInput(COLOR2); // target color + compiler->addInput(COLOR); // mask color + compiler->addFunctionCall(&colorIsTouchingColor); +} + void SensingBlocks::compileDistanceTo(Compiler *compiler) { Input *input = compiler->input(DISTANCETOMENU); @@ -525,6 +534,12 @@ unsigned int SensingBlocks::touchingColor(VirtualMachine *vm) return 0; } +unsigned int SensingBlocks::colorIsTouchingColor(VirtualMachine *vm) +{ + vm->replaceReturnValue(vm->target()->touchingColor(*vm->getInput(0, 2), *vm->getInput(1, 2)), 2); + return 1; +} + unsigned int SensingBlocks::keyPressed(VirtualMachine *vm) { vm->replaceReturnValue(vm->engine()->keyPressed(vm->getInput(0, 1)->toString()), 1); diff --git a/src/blocks/sensingblocks.h b/src/blocks/sensingblocks.h index e281827f..1d7e1903 100644 --- a/src/blocks/sensingblocks.h +++ b/src/blocks/sensingblocks.h @@ -22,6 +22,7 @@ class SensingBlocks : public IBlockSection { TOUCHINGOBJECTMENU, COLOR, + COLOR2, DISTANCETOMENU, QUESTION, KEY_OPTION, @@ -64,6 +65,7 @@ class SensingBlocks : public IBlockSection static void compileTouchingObject(Compiler *compiler); static void compileTouchingColor(Compiler *compiler); + static void compileColorIsTouchingColor(Compiler *compiler); static void compileDistanceTo(Compiler *compiler); static void compileAskAndWait(Compiler *compiler); static void compileAnswer(Compiler *compiler); @@ -95,6 +97,8 @@ class SensingBlocks : public IBlockSection static unsigned int touchingColor(VirtualMachine *vm); + static unsigned int colorIsTouchingColor(VirtualMachine *vm); + static unsigned int keyPressed(VirtualMachine *vm); static unsigned int mouseDown(VirtualMachine *vm); static unsigned int mouseX(VirtualMachine *vm); diff --git a/test/blocks/sensing_blocks_test.cpp b/test/blocks/sensing_blocks_test.cpp index ecc61337..d5afbde1 100644 --- a/test/blocks/sensing_blocks_test.cpp +++ b/test/blocks/sensing_blocks_test.cpp @@ -127,6 +127,7 @@ TEST_F(SensingBlocksTest, RegisterBlocks) // Blocks EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "sensing_touchingobject", &SensingBlocks::compileTouchingObject)); EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "sensing_touchingcolor", &SensingBlocks::compileTouchingColor)); + EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "sensing_coloristouchingcolor", &SensingBlocks::compileColorIsTouchingColor)); EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "sensing_distanceto", &SensingBlocks::compileDistanceTo)); EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "sensing_askandwait", &SensingBlocks::compileAskAndWait)); EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "sensing_answer", &SensingBlocks::compileAnswer)); @@ -155,6 +156,7 @@ TEST_F(SensingBlocksTest, RegisterBlocks) // Inputs EXPECT_CALL(m_engineMock, addInput(m_section.get(), "TOUCHINGOBJECTMENU", SensingBlocks::TOUCHINGOBJECTMENU)); EXPECT_CALL(m_engineMock, addInput(m_section.get(), "COLOR", SensingBlocks::COLOR)); + EXPECT_CALL(m_engineMock, addInput(m_section.get(), "COLOR2", SensingBlocks::COLOR2)); EXPECT_CALL(m_engineMock, addInput(m_section.get(), "DISTANCETOMENU", SensingBlocks::DISTANCETOMENU)); EXPECT_CALL(m_engineMock, addInput(m_section.get(), "QUESTION", SensingBlocks::QUESTION)); EXPECT_CALL(m_engineMock, addInput(m_section.get(), "KEY_OPTION", SensingBlocks::KEY_OPTION)); @@ -454,6 +456,79 @@ TEST_F(SensingBlocksTest, TouchingColorImpl) ASSERT_TRUE(vm.getInput(0, 1)->toBool()); } +TEST_F(SensingBlocksTest, ColorIsTouchingColor) +{ + Compiler compiler(&m_engineMock); + + // color (#FF00FF) is touching color (#FFFF00) + auto block1 = std::make_shared("a", "sensing_coloristouchingcolor"); + addValueInput(block1, "COLOR", SensingBlocks::COLOR, "#FF00FF"); + addValueInput(block1, "COLOR2", SensingBlocks::COLOR2, "#FFFF00"); + + // color (null block) is touching color (null block) + auto block2 = std::make_shared("b", "sensing_coloristouchingcolor"); + addDropdownInput(block2, "COLOR", SensingBlocks::COLOR, "", createNullBlock("c")); + addDropdownInput(block2, "COLOR2", SensingBlocks::COLOR2, "", createNullBlock("d")); + + compiler.init(); + + EXPECT_CALL(m_engineMock, functionIndex(&SensingBlocks::colorIsTouchingColor)).WillOnce(Return(1)); + compiler.setBlock(block1); + SensingBlocks::compileColorIsTouchingColor(&compiler); + + EXPECT_CALL(m_engineMock, functionIndex(&SensingBlocks::colorIsTouchingColor)).WillOnce(Return(1)); + compiler.setBlock(block2); + SensingBlocks::compileColorIsTouchingColor(&compiler); + + compiler.end(); + + ASSERT_EQ(compiler.bytecode(), std::vector({ vm::OP_START, vm::OP_CONST, 0, vm::OP_CONST, 1, vm::OP_EXEC, 1, vm::OP_NULL, vm::OP_NULL, vm::OP_EXEC, 1, vm::OP_HALT })); + ASSERT_EQ(compiler.constValues(), std::vector({ "#FFFF00", "#FF00FF" })); +} + +TEST_F(SensingBlocksTest, ColorIsTouchingColorImpl) +{ + static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_CONST, 1, vm::OP_EXEC, 0, vm::OP_HALT }; + static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 2, vm::OP_CONST, 3, vm::OP_EXEC, 0, vm::OP_HALT }; + static BlockFunc functions[] = { &SensingBlocks::colorIsTouchingColor }; + static Value constValues[] = { "#FF00FF", "#FFFF00", 1946195606, 238 }; + + TargetMock target; + Sprite sprite; + VirtualMachine vm(&target, nullptr, nullptr); + vm.setFunctions(functions); + vm.setConstValues(constValues); + + EXPECT_CALL(target, touchingColor(constValues[0], constValues[1])).WillOnce(Return(false)); + vm.setBytecode(bytecode1); + vm.run(); + + ASSERT_EQ(vm.registerCount(), 1); + ASSERT_FALSE(vm.getInput(0, 1)->toBool()); + + EXPECT_CALL(target, touchingColor(constValues[0], constValues[1])).WillOnce(Return(true)); + vm.reset(); + vm.run(); + + ASSERT_EQ(vm.registerCount(), 1); + ASSERT_TRUE(vm.getInput(0, 1)->toBool()); + + EXPECT_CALL(target, touchingColor(constValues[2], constValues[3])).WillOnce(Return(false)); + vm.reset(); + vm.setBytecode(bytecode2); + vm.run(); + + ASSERT_EQ(vm.registerCount(), 1); + ASSERT_FALSE(vm.getInput(0, 1)->toBool()); + + EXPECT_CALL(target, touchingColor(constValues[2], constValues[3])).WillOnce(Return(true)); + vm.reset(); + vm.run(); + + ASSERT_EQ(vm.registerCount(), 1); + ASSERT_TRUE(vm.getInput(0, 1)->toBool()); +} + TEST_F(SensingBlocksTest, DistanceTo) { Compiler compiler(&m_engineMock);