3
3
#include < scratchcpp/iengine.h>
4
4
#include < scratchcpp/compiler.h>
5
5
#include < scratchcpp/sprite.h>
6
+ #include < scratchcpp/input.h>
6
7
7
8
#include " motionblocks.h"
9
+ #include " ../engine/internal/randomgenerator.h"
8
10
9
11
using namespace libscratchcpp ;
10
12
11
13
static const double pi = std::acos(-1 ); // TODO: Use std::numbers::pi in C++20
12
14
15
+ IRandomGenerator *MotionBlocks::rng = nullptr ;
16
+
13
17
std::string MotionBlocks::name () const
14
18
{
15
19
return " Motion" ;
@@ -22,11 +26,13 @@ void MotionBlocks::registerBlocks(IEngine *engine)
22
26
engine->addCompileFunction (this , " motion_turnright" , &compileTurnRight);
23
27
engine->addCompileFunction (this , " motion_turnleft" , &compileTurnLeft);
24
28
engine->addCompileFunction (this , " motion_pointindirection" , &compilePointInDirection);
29
+ engine->addCompileFunction (this , " motion_pointtowards" , &compilePointTowards);
25
30
26
31
// Inputs
27
32
engine->addInput (this , " STEPS" , STEPS);
28
33
engine->addInput (this , " DEGREES" , DEGREES);
29
34
engine->addInput (this , " DIRECTION" , DIRECTION);
35
+ engine->addInput (this , " TOWARDS" , TOWARDS);
30
36
}
31
37
32
38
void MotionBlocks::compileMoveSteps (Compiler *compiler)
@@ -53,6 +59,29 @@ void MotionBlocks::compilePointInDirection(Compiler *compiler)
53
59
compiler->addFunctionCall (&pointInDirection);
54
60
}
55
61
62
+ void MotionBlocks::compilePointTowards (Compiler *compiler)
63
+ {
64
+ Input *input = compiler->input (TOWARDS);
65
+
66
+ if (input->type () != Input::Type::ObscuredShadow) {
67
+ assert (input->pointsToDropdownMenu ());
68
+ std::string value = input->selectedMenuItem ();
69
+
70
+ if (value == " _mouse_" )
71
+ compiler->addFunctionCall (&pointTowardsMousePointer);
72
+ else if (value == " _random_" )
73
+ compiler->addFunctionCall (&pointTowardsRandomPosition);
74
+ else {
75
+ int index = compiler->engine ()->findTarget (value);
76
+ compiler->addConstValue (index);
77
+ compiler->addFunctionCall (&pointTowardsByIndex);
78
+ }
79
+ } else {
80
+ compiler->addInput (input);
81
+ compiler->addFunctionCall (&pointTowards);
82
+ }
83
+ }
84
+
56
85
unsigned int MotionBlocks::moveSteps (VirtualMachine *vm)
57
86
{
58
87
Sprite *sprite = dynamic_cast <Sprite *>(vm->target ());
@@ -96,3 +125,81 @@ unsigned int MotionBlocks::pointInDirection(VirtualMachine *vm)
96
125
97
126
return 1 ;
98
127
}
128
+
129
+ void MotionBlocks::pointTowardsPos (Sprite *sprite, double x, double y)
130
+ {
131
+ if (!sprite)
132
+ return ;
133
+
134
+ // https://en.scratch-wiki.info/wiki/Point_Towards_()_(block)#Workaround
135
+ double deltaX = x - sprite->x ();
136
+ double deltaY = y - sprite->y ();
137
+
138
+ if (deltaY == 0 ) {
139
+ if (deltaX < 0 )
140
+ sprite->setDirection (-90 );
141
+ else
142
+ sprite->setDirection (90 );
143
+ } else if (deltaY < 0 )
144
+ sprite->setDirection (180 + (180 / pi) * std::atan (deltaX / deltaY));
145
+ else
146
+ sprite->setDirection ((180 / pi) * std::atan (deltaX / deltaY));
147
+ }
148
+
149
+ unsigned int MotionBlocks::pointTowards (VirtualMachine *vm)
150
+ {
151
+ std::string value = vm->getInput (0 , 1 )->toString ();
152
+ Target *target;
153
+
154
+ if (value == " _mouse_" )
155
+ pointTowardsPos (dynamic_cast <Sprite *>(vm->target ()), vm->engine ()->mouseX (), vm->engine ()->mouseY ());
156
+ else if (value == " _random_" ) {
157
+ // TODO: Read stage size from engine (#224)
158
+ static const unsigned int stageWidth = 480 ;
159
+ static const unsigned int stageHeight = 360 ;
160
+
161
+ if (!rng)
162
+ rng = RandomGenerator::instance ().get ();
163
+
164
+ pointTowardsPos (dynamic_cast <Sprite *>(vm->target ()), rng->randint (-static_cast <int >(stageWidth / 2 ), stageWidth / 2 ), rng->randint (-static_cast <int >(stageHeight / 2 ), stageHeight / 2 ));
165
+ } else {
166
+ target = vm->engine ()->targetAt (vm->engine ()->findTarget (value));
167
+ Sprite *sprite = dynamic_cast <Sprite *>(target);
168
+
169
+ if (sprite)
170
+ pointTowardsPos (dynamic_cast <Sprite *>(vm->target ()), sprite->x (), sprite->y ());
171
+ }
172
+
173
+ return 1 ;
174
+ }
175
+
176
+ unsigned int MotionBlocks::pointTowardsByIndex (VirtualMachine *vm)
177
+ {
178
+ Target *target = vm->engine ()->targetAt (vm->getInput (0 , 1 )->toInt ());
179
+ Sprite *sprite = dynamic_cast <Sprite *>(target);
180
+
181
+ if (sprite)
182
+ pointTowardsPos (dynamic_cast <Sprite *>(vm->target ()), sprite->x (), sprite->y ());
183
+
184
+ return 1 ;
185
+ }
186
+
187
+ unsigned int MotionBlocks::pointTowardsMousePointer (VirtualMachine *vm)
188
+ {
189
+ pointTowardsPos (dynamic_cast <Sprite *>(vm->target ()), vm->engine ()->mouseX (), vm->engine ()->mouseY ());
190
+ return 0 ;
191
+ }
192
+
193
+ unsigned int MotionBlocks::pointTowardsRandomPosition (VirtualMachine *vm)
194
+ {
195
+ // TODO: Read stage size from engine (#224)
196
+ static const unsigned int stageWidth = 480 ;
197
+ static const unsigned int stageHeight = 360 ;
198
+
199
+ if (!rng)
200
+ rng = RandomGenerator::instance ().get ();
201
+
202
+ pointTowardsPos (dynamic_cast <Sprite *>(vm->target ()), rng->randint (-static_cast <int >(stageWidth / 2 ), stageWidth / 2 ), rng->randint (-static_cast <int >(stageHeight / 2 ), stageHeight / 2 ));
203
+
204
+ return 0 ;
205
+ }
0 commit comments