Skip to content

Implement sensing_coloristouchingcolor block #570

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/scratchcpp/ispritehandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions include/scratchcpp/istagehandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions include/scratchcpp/sprite.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions include/scratchcpp/stage.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions include/scratchcpp/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
15 changes: 15 additions & 0 deletions src/blocks/sensingblocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions src/blocks/sensingblocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class SensingBlocks : public IBlockSection
{
TOUCHINGOBJECTMENU,
COLOR,
COLOR2,
DISTANCETOMENU,
QUESTION,
KEY_OPTION,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
9 changes: 9 additions & 0 deletions src/scratch/sprite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
9 changes: 9 additions & 0 deletions src/scratch/stage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
6 changes: 6 additions & 0 deletions src/scratch/target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
75 changes: 75 additions & 0 deletions test/blocks/sensing_blocks_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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<Block>("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<Block>("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<unsigned int>({ 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<Value>({ "#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);
Expand Down
1 change: 1 addition & 0 deletions test/mocks/spritehandlermock.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ class SpriteHandlerMock : public ISpriteHandler
MOCK_METHOD(bool, touchingClones, (const std::vector<Sprite *> &), (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));
};
1 change: 1 addition & 0 deletions test/mocks/stagehandlermock.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ class StageHandlerMock : public IStageHandler
MOCK_METHOD(bool, touchingClones, (const std::vector<Sprite *> &), (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));
};
1 change: 1 addition & 0 deletions test/mocks/targetmock.h
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
7 changes: 7 additions & 0 deletions test/scratch_classes/sprite_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
Expand Down
7 changes: 7 additions & 0 deletions test/scratch_classes/stage_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions test/scratch_classes/target_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading