Skip to content

Commit 6286f64

Browse files
authored
Merge pull request #525 from scratchcpp/touching_object_block
Implement the touching object block
2 parents 70abbf2 + f5e6e99 commit 6286f64

File tree

18 files changed

+741
-11
lines changed

18 files changed

+741
-11
lines changed

include/scratchcpp/ispritehandler.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ class LIBSCRATCHCPP_EXPORT ISpriteHandler
7777
* \note The rectangle must be relative to the stage, so make sure to use the sprite's coordinates.
7878
*/
7979
virtual Rect fastBoundingRect() const = 0;
80+
81+
/*! Used to check whether the sprite touches any of the given sprite clones. */
82+
virtual bool touchingClones(const std::vector<Sprite *> &clones) const = 0;
83+
84+
/*! Used to check whether the sprite touches the given point (in Scratch coordinates). */
85+
virtual bool touchingPoint(double x, double y) const = 0;
8086
};
8187

8288
} // namespace libscratchcpp

include/scratchcpp/istagehandler.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
namespace libscratchcpp
99
{
1010

11+
class Sprite;
12+
1113
/*! \brief The IStageHandler class provides a stage interface for Scratch project players. */
1214
class LIBSCRATCHCPP_EXPORT IStageHandler
1315
{
@@ -43,6 +45,21 @@ class LIBSCRATCHCPP_EXPORT IStageHandler
4345

4446
/*! Called when the bubble text changes. */
4547
virtual void onBubbleTextChanged(const std::string &text) = 0;
48+
49+
/*! Used to get the bounding rectangle of the stage. */
50+
virtual Rect boundingRect() const = 0;
51+
52+
/*!
53+
* Used to get a less accurate bounding rectangle of the stage
54+
* which is calculated by transforming the costume rectangle.
55+
*/
56+
virtual Rect fastBoundingRect() const = 0;
57+
58+
/*! Used to check whether the stage touches any of the given sprite clones. */
59+
virtual bool touchingClones(const std::vector<Sprite *> &clones) const = 0;
60+
61+
/*! Used to check whether the stage touches the given point (in Scratch coordinates). */
62+
virtual bool touchingPoint(double x, double y) const = 0;
4663
};
4764

4865
} // namespace libscratchcpp

include/scratchcpp/sprite.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ namespace libscratchcpp
88
{
99

1010
class ISpriteHandler;
11-
class Rect;
1211
class IGraphicsEffect;
1312
class SpritePrivate;
1413

@@ -69,10 +68,12 @@ class LIBSCRATCHCPP_EXPORT Sprite
6968

7069
void setLayerOrder(int newLayerOrder) override;
7170

72-
Rect boundingRect() const;
73-
Rect fastBoundingRect() const;
71+
Rect boundingRect() const override;
72+
Rect fastBoundingRect() const override;
7473
void keepInFence(double newX, double newY, double *fencedX, double *fencedY) const;
7574

75+
bool touchingPoint(double x, double y) const override;
76+
7677
void setGraphicsEffectValue(IGraphicsEffect *effect, double value) override;
7778

7879
void clearGraphicsEffects() override;
@@ -82,6 +83,7 @@ class LIBSCRATCHCPP_EXPORT Sprite
8283

8384
private:
8485
Target *dataSource() const override;
86+
bool touchingClones(const std::vector<Sprite *> &clones) const override;
8587
void setXY(double x, double y);
8688

8789
spimpl::unique_impl_ptr<SpritePrivate> impl;

include/scratchcpp/stage.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ class LIBSCRATCHCPP_EXPORT Stage : public Target
4848
const std::string &textToSpeechLanguage() const;
4949
void setTextToSpeechLanguage(const std::string &newTextToSpeechLanguage);
5050

51+
Rect boundingRect() const override;
52+
Rect fastBoundingRect() const override;
53+
54+
bool touchingPoint(double x, double y) const override;
55+
5156
void setGraphicsEffectValue(IGraphicsEffect *effect, double value) override;
5257

5358
void clearGraphicsEffects() override;
@@ -56,6 +61,8 @@ class LIBSCRATCHCPP_EXPORT Stage : public Target
5661
virtual void setBubbleText(const std::string &text) override;
5762

5863
private:
64+
bool touchingClones(const std::vector<Sprite *> &clones) const override;
65+
5966
spimpl::unique_impl_ptr<StagePrivate> impl;
6067
};
6168

include/scratchcpp/target.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "global.h"
88
#include "spimpl.h"
9+
#include "rect.h"
910

1011
namespace libscratchcpp
1112
{
@@ -17,6 +18,7 @@ class Block;
1718
class Comment;
1819
class Costume;
1920
class Sound;
21+
class Sprite;
2022
class IGraphicsEffect;
2123
class TargetPrivate;
2224

@@ -84,6 +86,13 @@ class LIBSCRATCHCPP_EXPORT Target
8486
double volume() const;
8587
void setVolume(double newVolume);
8688

89+
virtual Rect boundingRect() const;
90+
virtual Rect fastBoundingRect() const;
91+
92+
bool touchingSprite(Sprite *sprite) const;
93+
virtual bool touchingPoint(double x, double y) const;
94+
bool touchingEdge() const;
95+
8796
double graphicsEffectValue(IGraphicsEffect *effect) const;
8897
virtual void setGraphicsEffectValue(IGraphicsEffect *effect, double value);
8998

@@ -102,6 +111,9 @@ class LIBSCRATCHCPP_EXPORT Target
102111
/*! Override this method to set a custom data source for blocks, assets, comments, etc. */
103112
virtual Target *dataSource() const { return nullptr; }
104113

114+
/*! Override this method to check whether the target touches the given sprite clones. */
115+
virtual bool touchingClones(const std::vector<Sprite *> &clones) const { return false; }
116+
105117
private:
106118
spimpl::unique_impl_ptr<TargetPrivate> impl;
107119
};

src/blocks/sensingblocks.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ std::string SensingBlocks::name() const
3030
void SensingBlocks::registerBlocks(IEngine *engine)
3131
{
3232
// Blocks
33+
engine->addCompileFunction(this, "sensing_touchingobject", &compileTouchingObject);
3334
engine->addCompileFunction(this, "sensing_distanceto", &compileDistanceTo);
3435
engine->addCompileFunction(this, "sensing_askandwait", &compileAskAndWait);
3536
engine->addCompileFunction(this, "sensing_answer", &compileAnswer);
@@ -56,6 +57,7 @@ void SensingBlocks::registerBlocks(IEngine *engine)
5657
engine->addMonitorNameFunction(this, "sensing_dayssince2000", &daysSince2000MonitorName);
5758

5859
// Inputs
60+
engine->addInput(this, "TOUCHINGOBJECTMENU", TOUCHINGOBJECTMENU);
5961
engine->addInput(this, "DISTANCETOMENU", DISTANCETOMENU);
6062
engine->addInput(this, "QUESTION", QUESTION);
6163
engine->addInput(this, "KEY_OPTION", KEY_OPTION);
@@ -91,6 +93,29 @@ void SensingBlocks::registerBlocks(IEngine *engine)
9193
engine->questionAnswered().connect(&onAnswer);
9294
}
9395

96+
void SensingBlocks::compileTouchingObject(Compiler *compiler)
97+
{
98+
Input *input = compiler->input(TOUCHINGOBJECTMENU);
99+
100+
if (input->type() != Input::Type::ObscuredShadow) {
101+
assert(input->pointsToDropdownMenu());
102+
std::string value = input->selectedMenuItem();
103+
104+
if (value == "_mouse_")
105+
compiler->addFunctionCall(&touchingMousePointer);
106+
else if (value == "_edge_")
107+
compiler->addFunctionCall(&touchingEdge);
108+
else {
109+
int index = compiler->engine()->findTarget(value);
110+
compiler->addConstValue(index);
111+
compiler->addFunctionCall(&touchingObjectByIndex);
112+
}
113+
} else {
114+
compiler->addInput(input);
115+
compiler->addFunctionCall(&touchingObject);
116+
}
117+
}
118+
94119
void SensingBlocks::compileDistanceTo(Compiler *compiler)
95120
{
96121
Input *input = compiler->input(DISTANCETOMENU);
@@ -435,6 +460,41 @@ const std::string &SensingBlocks::daysSince2000MonitorName(Block *block)
435460
return name;
436461
}
437462

463+
unsigned int SensingBlocks::touchingObject(VirtualMachine *vm)
464+
{
465+
std::string value = vm->getInput(0, 1)->toString();
466+
467+
if (value == "_mouse_")
468+
vm->replaceReturnValue(vm->target()->touchingPoint(vm->engine()->mouseX(), vm->engine()->mouseY()), 1);
469+
else if (value == "_edge_")
470+
vm->replaceReturnValue(vm->target()->touchingEdge(), 1);
471+
else {
472+
Target *target = vm->engine()->targetAt(vm->engine()->findTarget(value));
473+
vm->replaceReturnValue(touchingObjectCommon(vm->target(), target), 1);
474+
}
475+
476+
return 0;
477+
}
478+
479+
unsigned int SensingBlocks::touchingObjectByIndex(VirtualMachine *vm)
480+
{
481+
Target *target = vm->engine()->targetAt(vm->getInput(0, 1)->toInt());
482+
vm->replaceReturnValue(touchingObjectCommon(vm->target(), target), 1);
483+
return 0;
484+
}
485+
486+
unsigned int SensingBlocks::touchingMousePointer(VirtualMachine *vm)
487+
{
488+
vm->addReturnValue(vm->target()->touchingPoint(vm->engine()->mouseX(), vm->engine()->mouseY()));
489+
return 0;
490+
}
491+
492+
unsigned int SensingBlocks::touchingEdge(VirtualMachine *vm)
493+
{
494+
vm->addReturnValue(vm->target()->touchingEdge());
495+
return 0;
496+
}
497+
438498
unsigned int SensingBlocks::keyPressed(VirtualMachine *vm)
439499
{
440500
vm->replaceReturnValue(vm->engine()->keyPressed(vm->getInput(0, 1)->toString()), 1);
@@ -921,6 +981,14 @@ unsigned int SensingBlocks::daysSince2000(VirtualMachine *vm)
921981
return 0;
922982
}
923983

984+
bool SensingBlocks::touchingObjectCommon(Target *source, Target *target)
985+
{
986+
if (source && target && !target->isStage())
987+
return source->touchingSprite(static_cast<Sprite *>(target));
988+
989+
return false;
990+
}
991+
924992
void SensingBlocks::enqueueAsk(const std::string &question, VirtualMachine *vm)
925993
{
926994
// https://github.com/scratchfoundation/scratch-vm/blob/6055823f203a696165084b873e661713806583ec/src/blocks/scratch3_sensing.js#L117-L119

src/blocks/sensingblocks.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class SensingBlocks : public IBlockSection
2020
public:
2121
enum Inputs
2222
{
23+
TOUCHINGOBJECTMENU,
2324
DISTANCETOMENU,
2425
QUESTION,
2526
KEY_OPTION,
@@ -59,6 +60,7 @@ class SensingBlocks : public IBlockSection
5960

6061
void registerBlocks(IEngine *engine) override;
6162

63+
static void compileTouchingObject(Compiler *compiler);
6264
static void compileDistanceTo(Compiler *compiler);
6365
static void compileAskAndWait(Compiler *compiler);
6466
static void compileAnswer(Compiler *compiler);
@@ -83,6 +85,11 @@ class SensingBlocks : public IBlockSection
8385
static const std::string &currentMonitorName(Block *block);
8486
static const std::string &daysSince2000MonitorName(Block *block);
8587

88+
static unsigned int touchingObject(VirtualMachine *vm);
89+
static unsigned int touchingObjectByIndex(VirtualMachine *vm);
90+
static unsigned int touchingMousePointer(VirtualMachine *vm);
91+
static unsigned int touchingEdge(VirtualMachine *vm);
92+
8693
static unsigned int keyPressed(VirtualMachine *vm);
8794
static unsigned int mouseDown(VirtualMachine *vm);
8895
static unsigned int mouseX(VirtualMachine *vm);
@@ -154,6 +161,8 @@ class SensingBlocks : public IBlockSection
154161
bool wasStage = false;
155162
};
156163

164+
static bool touchingObjectCommon(Target *source, Target *target);
165+
157166
static void enqueueAsk(const std::string &question, VirtualMachine *vm);
158167
static void askNextQuestion();
159168

src/scratch/sprite.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ void Sprite::setLayerOrder(int newLayerOrder)
341341
impl->iface->onLayerOrderChanged(newLayerOrder);
342342
}
343343

344-
/*! Returns the bounding rectangle of the sprite. */
344+
/*! Overrides Target#boundingRect(). */
345345
Rect Sprite::boundingRect() const
346346
{
347347
if (!impl->iface)
@@ -350,10 +350,7 @@ Rect Sprite::boundingRect() const
350350
return impl->iface->boundingRect();
351351
}
352352

353-
/*!
354-
* Returns the less accurate bounding rectangle of the sprite
355-
* which is calculated by transforming the costume rectangle.
356-
*/
353+
/*! Overrides Target#fastBoundingRect(). */
357354
Rect Sprite::fastBoundingRect() const
358355
{
359356
if (!impl->iface)
@@ -409,6 +406,15 @@ void Sprite::keepInFence(double newX, double newY, double *fencedX, double *fenc
409406
*fencedY = newY + dy;
410407
}
411408

409+
/*! Overrides Target#touchingPoint(). */
410+
bool Sprite::touchingPoint(double x, double y) const
411+
{
412+
if (!impl->iface)
413+
return false;
414+
415+
return impl->iface->touchingPoint(x, y);
416+
}
417+
412418
/*! Overrides Target#setGraphicsEffectValue(). */
413419
void Sprite::setGraphicsEffectValue(IGraphicsEffect *effect, double value)
414420
{
@@ -471,6 +477,14 @@ Target *Sprite::dataSource() const
471477
return impl->cloneSprite;
472478
}
473479

480+
bool Sprite::touchingClones(const std::vector<Sprite *> &clones) const
481+
{
482+
if (!impl->iface)
483+
return false;
484+
485+
return impl->iface->touchingClones(clones);
486+
}
487+
474488
void Sprite::setXY(double x, double y)
475489
{
476490
IEngine *eng = engine();

src/scratch/stage.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,33 @@ void Stage::setTextToSpeechLanguage(const std::string &newTextToSpeechLanguage)
131131
impl->textToSpeechLanguage = newTextToSpeechLanguage;
132132
}
133133

134+
/*! Overrides Target#boundingRect(). */
135+
Rect Stage::boundingRect() const
136+
{
137+
if (!impl->iface)
138+
return Rect();
139+
140+
return impl->iface->boundingRect();
141+
}
142+
143+
/*! Overrides Target#boundingRect(). */
144+
Rect Stage::fastBoundingRect() const
145+
{
146+
if (!impl->iface)
147+
return Rect();
148+
149+
return impl->iface->fastBoundingRect();
150+
}
151+
152+
/*! Overrides Target#touchingPoint(). */
153+
bool Stage::touchingPoint(double x, double y) const
154+
{
155+
if (!impl->iface)
156+
return false;
157+
158+
return impl->iface->touchingPoint(x, y);
159+
}
160+
134161
/*! Overrides Target#setGraphicsEffectValue(). */
135162
void Stage::setGraphicsEffectValue(IGraphicsEffect *effect, double value)
136163
{
@@ -181,3 +208,11 @@ void Stage::setBubbleText(const std::string &text)
181208
if (impl->iface)
182209
impl->iface->onBubbleTextChanged(text);
183210
}
211+
212+
bool Stage::touchingClones(const std::vector<Sprite *> &clones) const
213+
{
214+
if (!impl->iface)
215+
return false;
216+
217+
return impl->iface->touchingClones(clones);
218+
}

0 commit comments

Comments
 (0)