Skip to content

Commit 734a172

Browse files
committed
Implement motion_pointtowards block
1 parent 80a651e commit 734a172

File tree

3 files changed

+344
-1
lines changed

3 files changed

+344
-1
lines changed

src/blocks/motionblocks.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
#include <scratchcpp/iengine.h>
44
#include <scratchcpp/compiler.h>
55
#include <scratchcpp/sprite.h>
6+
#include <scratchcpp/input.h>
67

78
#include "motionblocks.h"
9+
#include "../engine/internal/randomgenerator.h"
810

911
using namespace libscratchcpp;
1012

1113
static const double pi = std::acos(-1); // TODO: Use std::numbers::pi in C++20
1214

15+
IRandomGenerator *MotionBlocks::rng = nullptr;
16+
1317
std::string MotionBlocks::name() const
1418
{
1519
return "Motion";
@@ -22,11 +26,13 @@ void MotionBlocks::registerBlocks(IEngine *engine)
2226
engine->addCompileFunction(this, "motion_turnright", &compileTurnRight);
2327
engine->addCompileFunction(this, "motion_turnleft", &compileTurnLeft);
2428
engine->addCompileFunction(this, "motion_pointindirection", &compilePointInDirection);
29+
engine->addCompileFunction(this, "motion_pointtowards", &compilePointTowards);
2530

2631
// Inputs
2732
engine->addInput(this, "STEPS", STEPS);
2833
engine->addInput(this, "DEGREES", DEGREES);
2934
engine->addInput(this, "DIRECTION", DIRECTION);
35+
engine->addInput(this, "TOWARDS", TOWARDS);
3036
}
3137

3238
void MotionBlocks::compileMoveSteps(Compiler *compiler)
@@ -53,6 +59,29 @@ void MotionBlocks::compilePointInDirection(Compiler *compiler)
5359
compiler->addFunctionCall(&pointInDirection);
5460
}
5561

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+
5685
unsigned int MotionBlocks::moveSteps(VirtualMachine *vm)
5786
{
5887
Sprite *sprite = dynamic_cast<Sprite *>(vm->target());
@@ -96,3 +125,81 @@ unsigned int MotionBlocks::pointInDirection(VirtualMachine *vm)
96125

97126
return 1;
98127
}
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+
}

src/blocks/motionblocks.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
namespace libscratchcpp
88
{
99

10+
class Sprite;
11+
class IRandomGenerator;
12+
1013
/*! \brief The MotionBlocks class contains the implementation of motion blocks. */
1114
class MotionBlocks : public IBlockSection
1215
{
@@ -15,7 +18,16 @@ class MotionBlocks : public IBlockSection
1518
{
1619
STEPS,
1720
DEGREES,
18-
DIRECTION
21+
DIRECTION,
22+
TOWARDS
23+
};
24+
25+
enum Fields
26+
{
27+
};
28+
29+
enum FieldValues
30+
{
1931
};
2032

2133
std::string name() const override;
@@ -26,11 +38,21 @@ class MotionBlocks : public IBlockSection
2638
static void compileTurnRight(Compiler *compiler);
2739
static void compileTurnLeft(Compiler *compiler);
2840
static void compilePointInDirection(Compiler *compiler);
41+
static void compilePointTowards(Compiler *compiler);
2942

3043
static unsigned int moveSteps(VirtualMachine *vm);
3144
static unsigned int turnRight(VirtualMachine *vm);
3245
static unsigned int turnLeft(VirtualMachine *vm);
3346
static unsigned int pointInDirection(VirtualMachine *vm);
47+
48+
static void pointTowardsPos(Sprite *sprite, double x, double y);
49+
50+
static unsigned int pointTowards(VirtualMachine *vm);
51+
static unsigned int pointTowardsByIndex(VirtualMachine *vm);
52+
static unsigned int pointTowardsMousePointer(VirtualMachine *vm);
53+
static unsigned int pointTowardsRandomPosition(VirtualMachine *vm);
54+
55+
static IRandomGenerator *rng;
3456
};
3557

3658
} // namespace libscratchcpp

0 commit comments

Comments
 (0)