Skip to content

Commit 2fa60f7

Browse files
authored
Merge pull request #473 from scratchcpp/target_click_blocks
Implement target click event blocks
2 parents 0f54bd2 + cd81439 commit 2fa60f7

File tree

9 files changed

+156
-7
lines changed

9 files changed

+156
-7
lines changed

include/scratchcpp/iengine.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,9 @@ class LIBSCRATCHCPP_EXPORT IEngine
289289
/* Registers the given "when key pressed" script. */
290290
virtual void addKeyPressScript(std::shared_ptr<Block> hatBlock, int fieldId) = 0;
291291

292+
/* Registers the given "when this sprite/stage clicked" script. */
293+
virtual void addTargetClickScript(std::shared_ptr<Block> hatBlock) = 0;
294+
292295
/*! Returns the list of targets. */
293296
virtual const std::vector<std::shared_ptr<Target>> &targets() const = 0;
294297

src/blocks/eventblocks.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ void EventBlocks::registerBlocks(IEngine *engine)
2222
{
2323
// Blocks
2424
engine->addCompileFunction(this, "event_whenflagclicked", &compileWhenFlagClicked);
25+
engine->addCompileFunction(this, "event_whenthisspriteclicked", &compileWhenThisSpriteClicked);
26+
engine->addCompileFunction(this, "event_whenstageclicked", &compileWhenStageClicked);
2527
engine->addCompileFunction(this, "event_broadcast", &compileBroadcast);
2628
engine->addCompileFunction(this, "event_broadcastandwait", &compileBroadcastAndWait);
2729
engine->addCompileFunction(this, "event_whenbroadcastreceived", &compileWhenBroadcastReceived);
@@ -42,6 +44,16 @@ void EventBlocks::compileWhenFlagClicked(Compiler *compiler)
4244
compiler->engine()->addGreenFlagScript(compiler->block());
4345
}
4446

47+
void EventBlocks::compileWhenThisSpriteClicked(Compiler *compiler)
48+
{
49+
compiler->engine()->addTargetClickScript(compiler->block());
50+
}
51+
52+
void EventBlocks::compileWhenStageClicked(Compiler *compiler)
53+
{
54+
compiler->engine()->addTargetClickScript(compiler->block());
55+
}
56+
4557
void EventBlocks::compileBroadcast(Compiler *compiler)
4658
{
4759
auto input = compiler->input(BROADCAST_INPUT);

src/blocks/eventblocks.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class EventBlocks : public IBlockSection
3131
void registerBlocks(IEngine *engine) override;
3232

3333
static void compileWhenFlagClicked(Compiler *compiler);
34+
static void compileWhenThisSpriteClicked(Compiler *compiler);
35+
static void compileWhenStageClicked(Compiler *compiler);
3436
static void compileBroadcast(Compiler *compiler);
3537
static void compileBroadcastAndWait(Compiler *compiler);
3638
static void compileWhenBroadcastReceived(Compiler *compiler);

src/engine/internal/engine.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,8 @@
3434
using namespace libscratchcpp;
3535

3636
const std::unordered_map<Engine::HatType, bool> Engine::m_hatRestartExistingThreads = {
37-
{ HatType::GreenFlag, true },
38-
{ HatType::BroadcastReceived, true },
39-
{ HatType::BackdropChanged, true },
40-
{ HatType::CloneInit, false },
41-
{ HatType::KeyPressed, false }
37+
{ HatType::GreenFlag, true }, { HatType::BroadcastReceived, true }, { HatType::BackdropChanged, true },
38+
{ HatType::CloneInit, false }, { HatType::KeyPressed, false }, { HatType::TargetClicked, true }
4239
};
4340

4441
Engine::Engine() :
@@ -698,7 +695,7 @@ void Engine::setMousePressed(bool pressed)
698695

699696
void Engine::clickTarget(Target *target)
700697
{
701-
// TODO: Implement this (#92, #93)
698+
startHats(HatType::TargetClicked, {}, target);
702699
}
703700

704701
unsigned int Engine::stageWidth() const
@@ -981,6 +978,11 @@ void Engine::addKeyPressScript(std::shared_ptr<Block> hatBlock, int fieldId)
981978
addHatField(script, HatField::KeyOption, fieldId);
982979
}
983980

981+
void Engine::addTargetClickScript(std::shared_ptr<Block> hatBlock)
982+
{
983+
addHatToMap(m_whenTargetClickedHats, m_scripts[hatBlock].get());
984+
}
985+
984986
const std::vector<std::shared_ptr<Target>> &Engine::targets() const
985987
{
986988
return m_targets;
@@ -1366,6 +1368,9 @@ const std::vector<Script *> &Engine::getHats(Target *target, HatType type)
13661368
case HatType::KeyPressed:
13671369
return m_whenKeyPressedHats[target];
13681370

1371+
case HatType::TargetClicked:
1372+
return m_whenTargetClickedHats[target];
1373+
13691374
default: {
13701375
static const std::vector<Script *> empty = {};
13711376
return empty;

src/engine/internal/engine.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class Engine : public IEngine
123123
void addBackdropChangeScript(std::shared_ptr<Block> hatBlock, int fieldId) override;
124124
void addCloneInitScript(std::shared_ptr<Block> hatBlock) override;
125125
void addKeyPressScript(std::shared_ptr<Block> hatBlock, int fieldId) override;
126+
void addTargetClickScript(std::shared_ptr<Block> hatBlock) override;
126127

127128
const std::vector<std::shared_ptr<Target>> &targets() const override;
128129
void setTargets(const std::vector<std::shared_ptr<Target>> &newTargets) override;
@@ -159,7 +160,8 @@ class Engine : public IEngine
159160
BroadcastReceived,
160161
BackdropChanged,
161162
CloneInit,
162-
KeyPressed
163+
KeyPressed,
164+
TargetClicked
163165
};
164166

165167
enum class HatField
@@ -225,6 +227,7 @@ class Engine : public IEngine
225227
std::unordered_map<Target *, std::vector<Script *>> m_broadcastHats;
226228
std::unordered_map<Target *, std::vector<Script *>> m_cloneInitHats;
227229
std::unordered_map<Target *, std::vector<Script *>> m_whenKeyPressedHats;
230+
std::unordered_map<Target *, std::vector<Script *>> m_whenTargetClickedHats;
228231

229232
std::unordered_map<Script *, std::unordered_map<HatField, int>> m_scriptHatFields; // HatField, field ID from the block implementation
230233

test/blocks/event_blocks_test.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ TEST_F(EventBlocksTest, RegisterBlocks)
8484
{
8585
// Blocks
8686
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "event_whenflagclicked", &EventBlocks::compileWhenFlagClicked));
87+
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "event_whenthisspriteclicked", &EventBlocks::compileWhenThisSpriteClicked));
88+
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "event_whenstageclicked", &EventBlocks::compileWhenStageClicked));
8789
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "event_broadcast", &EventBlocks::compileBroadcast));
8890
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "event_broadcastandwait", &EventBlocks::compileBroadcastAndWait));
8991
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "event_whenbroadcastreceived", &EventBlocks::compileWhenBroadcastReceived));
@@ -121,6 +123,46 @@ TEST_F(EventBlocksTest, WhenFlagClicked)
121123
ASSERT_TRUE(compiler.lists().empty());
122124
}
123125

126+
TEST_F(EventBlocksTest, WhenThisSpriteClicked)
127+
{
128+
Compiler compiler(&m_engineMock);
129+
130+
auto block = createEventBlock("a", "event_whenthisspriteclicked");
131+
132+
compiler.init();
133+
134+
EXPECT_CALL(m_engineMock, addTargetClickScript(block));
135+
compiler.setBlock(block);
136+
EventBlocks::compileWhenThisSpriteClicked(&compiler);
137+
138+
compiler.end();
139+
140+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_HALT }));
141+
ASSERT_TRUE(compiler.constValues().empty());
142+
ASSERT_TRUE(compiler.variables().empty());
143+
ASSERT_TRUE(compiler.lists().empty());
144+
}
145+
146+
TEST_F(EventBlocksTest, WhenStageClicked)
147+
{
148+
Compiler compiler(&m_engineMock);
149+
150+
auto block = createEventBlock("a", "event_whenstageclicked");
151+
152+
compiler.init();
153+
154+
EXPECT_CALL(m_engineMock, addTargetClickScript(block));
155+
compiler.setBlock(block);
156+
EventBlocks::compileWhenStageClicked(&compiler);
157+
158+
compiler.end();
159+
160+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_HALT }));
161+
ASSERT_TRUE(compiler.constValues().empty());
162+
ASSERT_TRUE(compiler.variables().empty());
163+
ASSERT_TRUE(compiler.lists().empty());
164+
}
165+
124166
TEST_F(EventBlocksTest, Broadcast)
125167
{
126168
Compiler compiler(&m_engineMock);

test/engine/engine_test.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,87 @@ TEST(EngineTest, Broadcasts)
10551055
ASSERT_EQ(engine.findBroadcastById("c"), 2);
10561056
}
10571057

1058+
TEST(EngineTest, TargetClickScripts)
1059+
{
1060+
Project p("target_click_scripts.sb3");
1061+
ASSERT_TRUE(p.load());
1062+
p.run();
1063+
1064+
auto engine = p.engine();
1065+
1066+
Stage *stage = engine->stage();
1067+
ASSERT_TRUE(stage);
1068+
1069+
// Initial state
1070+
ASSERT_VAR(stage, "1");
1071+
ASSERT_EQ(GET_VAR(stage, "1")->value().toInt(), 0);
1072+
ASSERT_VAR(stage, "2");
1073+
ASSERT_EQ(GET_VAR(stage, "2")->value().toInt(), 0);
1074+
ASSERT_VAR(stage, "stage");
1075+
ASSERT_EQ(GET_VAR(stage, "stage")->value().toInt(), 0);
1076+
1077+
// Sprite1
1078+
Target *sprite = engine->targetAt(engine->findTarget("Sprite1"));
1079+
ASSERT_TRUE(sprite);
1080+
engine->clickTarget(sprite);
1081+
engine->step();
1082+
ASSERT_VAR(stage, "1");
1083+
ASSERT_EQ(GET_VAR(stage, "1")->value().toInt(), 1);
1084+
ASSERT_VAR(stage, "2");
1085+
ASSERT_EQ(GET_VAR(stage, "2")->value().toInt(), 0);
1086+
ASSERT_VAR(stage, "stage");
1087+
ASSERT_EQ(GET_VAR(stage, "stage")->value().toInt(), 0);
1088+
1089+
engine->clickTarget(sprite);
1090+
engine->step();
1091+
ASSERT_VAR(stage, "1");
1092+
ASSERT_EQ(GET_VAR(stage, "1")->value().toInt(), 2);
1093+
ASSERT_VAR(stage, "2");
1094+
ASSERT_EQ(GET_VAR(stage, "2")->value().toInt(), 0);
1095+
ASSERT_VAR(stage, "stage");
1096+
ASSERT_EQ(GET_VAR(stage, "stage")->value().toInt(), 0);
1097+
1098+
// Sprite2
1099+
sprite = engine->targetAt(engine->findTarget("Sprite2"));
1100+
ASSERT_TRUE(sprite);
1101+
engine->clickTarget(sprite);
1102+
engine->step();
1103+
ASSERT_VAR(stage, "1");
1104+
ASSERT_EQ(GET_VAR(stage, "1")->value().toInt(), 2);
1105+
ASSERT_VAR(stage, "2");
1106+
ASSERT_EQ(GET_VAR(stage, "2")->value().toInt(), 1);
1107+
ASSERT_VAR(stage, "stage");
1108+
ASSERT_EQ(GET_VAR(stage, "stage")->value().toInt(), 0);
1109+
1110+
engine->clickTarget(sprite);
1111+
engine->step();
1112+
ASSERT_VAR(stage, "1");
1113+
ASSERT_EQ(GET_VAR(stage, "1")->value().toInt(), 2);
1114+
ASSERT_VAR(stage, "2");
1115+
ASSERT_EQ(GET_VAR(stage, "2")->value().toInt(), 2);
1116+
ASSERT_VAR(stage, "stage");
1117+
ASSERT_EQ(GET_VAR(stage, "stage")->value().toInt(), 0);
1118+
1119+
// Stage
1120+
engine->clickTarget(stage);
1121+
engine->step();
1122+
ASSERT_VAR(stage, "1");
1123+
ASSERT_EQ(GET_VAR(stage, "1")->value().toInt(), 2);
1124+
ASSERT_VAR(stage, "2");
1125+
ASSERT_EQ(GET_VAR(stage, "2")->value().toInt(), 2);
1126+
ASSERT_VAR(stage, "stage");
1127+
ASSERT_EQ(GET_VAR(stage, "stage")->value().toInt(), 1);
1128+
1129+
engine->clickTarget(stage);
1130+
engine->step();
1131+
ASSERT_VAR(stage, "1");
1132+
ASSERT_EQ(GET_VAR(stage, "1")->value().toInt(), 2);
1133+
ASSERT_VAR(stage, "2");
1134+
ASSERT_EQ(GET_VAR(stage, "2")->value().toInt(), 2);
1135+
ASSERT_VAR(stage, "stage");
1136+
ASSERT_EQ(GET_VAR(stage, "stage")->value().toInt(), 2);
1137+
}
1138+
10581139
TEST(EngineTest, Targets)
10591140
{
10601141
Engine engine;

test/mocks/enginemock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class EngineMock : public IEngine
104104
MOCK_METHOD(void, addBackdropChangeScript, (std::shared_ptr<Block>, int), (override));
105105
MOCK_METHOD(void, addCloneInitScript, (std::shared_ptr<Block>), (override));
106106
MOCK_METHOD(void, addKeyPressScript, (std::shared_ptr<Block>, int), (override));
107+
MOCK_METHOD(void, addTargetClickScript, (std::shared_ptr<Block>), (override));
107108

108109
MOCK_METHOD(const std::vector<std::shared_ptr<Target>> &, targets, (), (const, override));
109110
MOCK_METHOD(void, setTargets, (const std::vector<std::shared_ptr<Target>> &), (override));

test/target_click_scripts.sb3

1.53 KB
Binary file not shown.

0 commit comments

Comments
 (0)