Skip to content

Commit a4f2057

Browse files
committed
Implement motion_pointtowards block
1 parent d4fc993 commit a4f2057

File tree

3 files changed

+391
-0
lines changed

3 files changed

+391
-0
lines changed

src/blocks/motionblocks.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,17 @@
22

33
#include <scratchcpp/iengine.h>
44
#include <scratchcpp/compiler.h>
5+
#include <scratchcpp/compilerconstant.h>
56
#include <scratchcpp/sprite.h>
7+
#include <scratchcpp/input.h>
8+
#include <scratchcpp/value.h>
9+
#include <scratchcpp/executioncontext.h>
10+
#include <scratchcpp/thread.h>
11+
#include <scratchcpp/irandomgenerator.h>
12+
#include <scratchcpp/stringptr.h>
13+
#include <scratchcpp/string_functions.h>
614
#include <cmath>
15+
#include <utf8.h>
716

817
#include "motionblocks.h"
918

@@ -32,6 +41,7 @@ void MotionBlocks::registerBlocks(IEngine *engine)
3241
engine->addCompileFunction(this, "motion_turnright", &compileTurnRight);
3342
engine->addCompileFunction(this, "motion_turnleft", &compileTurnLeft);
3443
engine->addCompileFunction(this, "motion_pointindirection", &compilePointInDirection);
44+
engine->addCompileFunction(this, "motion_pointtowards", &compilePointTowards);
3545
}
3646

3747
CompilerValue *MotionBlocks::compileMoveSteps(Compiler *compiler)
@@ -74,6 +84,35 @@ CompilerValue *MotionBlocks::compilePointInDirection(Compiler *compiler)
7484
return nullptr;
7585
}
7686

87+
CompilerValue *MotionBlocks::compilePointTowards(Compiler *compiler)
88+
{
89+
if (compiler->target()->isStage())
90+
return nullptr;
91+
92+
Input *input = compiler->input("TOWARDS");
93+
94+
if (input->pointsToDropdownMenu()) {
95+
std::string value = input->selectedMenuItem();
96+
97+
if (value == "_mouse_")
98+
compiler->addTargetFunctionCall("motion_point_towards_mouse");
99+
else if (value == "_random_")
100+
compiler->addFunctionCallWithCtx("motion_point_towards_random_pos");
101+
else {
102+
int index = compiler->engine()->findTarget(value);
103+
Target *anotherTarget = compiler->engine()->targetAt(index);
104+
105+
if (anotherTarget && !anotherTarget->isStage())
106+
compiler->addTargetFunctionCall("motion_point_towards_target_by_index", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { compiler->addConstValue(index) });
107+
}
108+
} else {
109+
CompilerValue *towards = compiler->addInput(input);
110+
compiler->addFunctionCallWithCtx("motion_pointtowards", Compiler::StaticType::Void, { Compiler::StaticType::String }, { towards });
111+
}
112+
113+
return nullptr;
114+
}
115+
77116
extern "C" void motion_movesteps(Sprite *sprite, double steps)
78117
{
79118
double dir = sprite->direction();
@@ -94,3 +133,66 @@ extern "C" void motion_pointindirection(Sprite *sprite, double direction)
94133
{
95134
sprite->setDirection(direction);
96135
}
136+
137+
inline void motion_point_towards_pos(Sprite *sprite, double x, double y)
138+
{
139+
// https://en.scratch-wiki.info/wiki/Point_Towards_()_(block)#Workaround
140+
double deltaX = x - sprite->x();
141+
double deltaY = y - sprite->y();
142+
143+
if (deltaY == 0) {
144+
if (deltaX < 0)
145+
sprite->setDirection(-90);
146+
else
147+
sprite->setDirection(90);
148+
} else if (deltaY < 0)
149+
sprite->setDirection(180 + (180 / pi) * std::atan(deltaX / deltaY));
150+
else
151+
sprite->setDirection((180 / pi) * std::atan(deltaX / deltaY));
152+
}
153+
154+
extern "C" void motion_point_towards_mouse(Sprite *sprite)
155+
{
156+
IEngine *engine = sprite->engine();
157+
motion_point_towards_pos(sprite, engine->mouseX(), engine->mouseY());
158+
}
159+
160+
extern "C" void motion_point_towards_random_pos(ExecutionContext *ctx)
161+
{
162+
Sprite *sprite = static_cast<Sprite *>(ctx->thread()->target());
163+
IEngine *engine = ctx->engine();
164+
const int stageWidth = engine->stageWidth();
165+
const int stageHeight = engine->stageHeight();
166+
IRandomGenerator *rng = ctx->rng();
167+
motion_point_towards_pos(sprite, rng->randintDouble(-stageWidth / 2.0, stageWidth / 2.0), rng->randintDouble(-stageHeight / 2.0, stageHeight / 2.0));
168+
}
169+
170+
extern "C" void motion_point_towards_target_by_index(Sprite *sprite, double index)
171+
{
172+
Sprite *anotherSprite = static_cast<Sprite *>(sprite->engine()->targetAt(index));
173+
motion_point_towards_pos(sprite, anotherSprite->x(), anotherSprite->y());
174+
}
175+
176+
extern "C" void motion_pointtowards(ExecutionContext *ctx, const StringPtr *towards)
177+
{
178+
static const StringPtr MOUSE_STR("_mouse_");
179+
static const StringPtr RANDOM_STR("_random_");
180+
181+
Sprite *sprite = static_cast<Sprite *>(ctx->thread()->target());
182+
183+
if (string_compare_case_sensitive(towards, &MOUSE_STR) == 0)
184+
motion_point_towards_mouse(sprite);
185+
else if (string_compare_case_sensitive(towards, &RANDOM_STR) == 0)
186+
motion_point_towards_random_pos(ctx);
187+
else {
188+
// TODO: Use UTF-16 in engine
189+
std::string u8name = utf8::utf16to8(std::u16string(towards->data));
190+
IEngine *engine = ctx->engine();
191+
Target *anotherTarget = engine->targetAt(engine->findTarget(u8name));
192+
193+
if (anotherTarget && !anotherTarget->isStage()) {
194+
Sprite *anotherSprite = static_cast<Sprite *>(anotherTarget);
195+
motion_point_towards_pos(sprite, anotherSprite->x(), anotherSprite->y());
196+
}
197+
}
198+
}

src/blocks/motionblocks.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class MotionBlocks : public IExtension
2121
static CompilerValue *compileTurnRight(Compiler *compiler);
2222
static CompilerValue *compileTurnLeft(Compiler *compiler);
2323
static CompilerValue *compilePointInDirection(Compiler *compiler);
24+
static CompilerValue *compilePointTowards(Compiler *compiler);
2425
};
2526

2627
} // namespace libscratchcpp

0 commit comments

Comments
 (0)