Skip to content

Commit 3fe0fe6

Browse files
committed
Implement motion_glidesecstoxy block
1 parent 9b42803 commit 3fe0fe6

File tree

3 files changed

+158
-0
lines changed

3 files changed

+158
-0
lines changed

src/blocks/motionblocks.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <scratchcpp/executioncontext.h>
1010
#include <scratchcpp/thread.h>
1111
#include <scratchcpp/irandomgenerator.h>
12+
#include <scratchcpp/istacktimer.h>
1213
#include <scratchcpp/stringptr.h>
1314
#include <scratchcpp/string_functions.h>
1415
#include <cmath>
@@ -44,6 +45,7 @@ void MotionBlocks::registerBlocks(IEngine *engine)
4445
engine->addCompileFunction(this, "motion_pointtowards", &compilePointTowards);
4546
engine->addCompileFunction(this, "motion_gotoxy", &compileGoToXY);
4647
engine->addCompileFunction(this, "motion_goto", &compileGoTo);
48+
engine->addCompileFunction(this, "motion_glidesecstoxy", &compileGlideSecsToXY);
4749
}
4850

4951
CompilerValue *MotionBlocks::compileMoveSteps(Compiler *compiler)
@@ -155,6 +157,27 @@ CompilerValue *MotionBlocks::compileGoTo(Compiler *compiler)
155157
return nullptr;
156158
}
157159

160+
CompilerValue *MotionBlocks::compileGlideSecsToXY(Compiler *compiler)
161+
{
162+
Target *target = compiler->target();
163+
CompilerValue *duration = compiler->addInput("SECS");
164+
CompilerValue *startX = target->isStage() ? compiler->addConstValue(0) : compiler->addTargetFunctionCall("motion_xposition", Compiler::StaticType::Number);
165+
CompilerValue *startY = target->isStage() ? compiler->addConstValue(0) : compiler->addTargetFunctionCall("motion_yposition", Compiler::StaticType::Number);
166+
CompilerValue *endX = compiler->addInput("X");
167+
CompilerValue *endY = compiler->addInput("Y");
168+
169+
compiler->addFunctionCallWithCtx("motion_start_glide", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { duration });
170+
compiler->createYield();
171+
172+
compiler->beginLoopCondition();
173+
auto numType = Compiler::StaticType::Number;
174+
CompilerValue *elapsed = compiler->addFunctionCallWithCtx("motion_glide", Compiler::StaticType::Bool, { numType, numType, numType, numType, numType }, { duration, startX, startY, endX, endY });
175+
compiler->beginRepeatUntilLoop(elapsed);
176+
compiler->endLoop();
177+
178+
return nullptr;
179+
}
180+
158181
extern "C" void motion_movesteps(Sprite *sprite, double steps)
159182
{
160183
double dir = sprite->direction();
@@ -289,3 +312,44 @@ extern "C" void motion_goto(ExecutionContext *ctx, const StringPtr *towards)
289312
}
290313
}
291314
}
315+
316+
extern "C" void motion_start_glide(ExecutionContext *ctx, double duration)
317+
{
318+
ctx->stackTimer()->start(duration);
319+
}
320+
321+
extern "C" bool motion_glide(ExecutionContext *ctx, double duration, double startX, double startY, double endX, double endY)
322+
{
323+
IStackTimer *timer = ctx->stackTimer();
324+
Target *target = ctx->thread()->target();
325+
Sprite *sprite = nullptr;
326+
double elapsedTime = timer->elapsedTime();
327+
328+
if (!target->isStage())
329+
sprite = static_cast<Sprite *>(target);
330+
331+
if (elapsedTime >= duration) {
332+
if (sprite)
333+
sprite->setPosition(endX, endY);
334+
335+
return true;
336+
} else {
337+
if (sprite) {
338+
double factor = elapsedTime / duration;
339+
assert(factor >= 0 && factor < 1);
340+
sprite->setPosition(startX + (endX - startX) * factor, startY + (endY - startY) * factor);
341+
}
342+
343+
return false;
344+
}
345+
}
346+
347+
extern "C" double motion_xposition(Sprite *sprite)
348+
{
349+
return sprite->x();
350+
}
351+
352+
extern "C" double motion_yposition(Sprite *sprite)
353+
{
354+
return sprite->y();
355+
}

src/blocks/motionblocks.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class MotionBlocks : public IExtension
2424
static CompilerValue *compilePointTowards(Compiler *compiler);
2525
static CompilerValue *compileGoToXY(Compiler *compiler);
2626
static CompilerValue *compileGoTo(Compiler *compiler);
27+
static CompilerValue *compileGlideSecsToXY(Compiler *compiler);
2728
};
2829

2930
} // namespace libscratchcpp

test/blocks/motion_blocks_test.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <scratchcpp/executioncontext.h>
1010
#include <enginemock.h>
1111
#include <randomgeneratormock.h>
12+
#include <stacktimermock.h>
1213

1314
#include "../common.h"
1415
#include "blocks/motionblocks.h"
@@ -847,3 +848,95 @@ TEST_F(MotionBlocksTest, GoToSprite)
847848
builder.run();
848849
}
849850
}
851+
852+
TEST_F(MotionBlocksTest, GlideSecsToXY)
853+
{
854+
{
855+
auto sprite = std::make_shared<Sprite>();
856+
sprite->setX(51.28);
857+
sprite->setY(-0.5);
858+
859+
ScriptBuilder builder(m_extension.get(), m_engine, sprite);
860+
861+
builder.addBlock("motion_glidesecstoxy");
862+
builder.addValueInput("SECS", 2.5);
863+
builder.addValueInput("X", -55.2);
864+
builder.addValueInput("Y", 23.254);
865+
auto block = builder.currentBlock();
866+
867+
Compiler compiler(&m_engineMock, sprite.get());
868+
auto code = compiler.compile(block);
869+
Script script(sprite.get(), block, &m_engineMock);
870+
script.setCode(code);
871+
Thread thread(sprite.get(), &m_engineMock, &script);
872+
auto ctx = code->createExecutionContext(&thread);
873+
StackTimerMock timer;
874+
ctx->setStackTimer(&timer);
875+
876+
EXPECT_CALL(timer, start(2.5));
877+
EXPECT_CALL(m_engineMock, requestRedraw()).WillRepeatedly(Return());
878+
code->run(ctx.get());
879+
ASSERT_FALSE(code->isFinished(ctx.get()));
880+
881+
EXPECT_CALL(timer, elapsedTime()).WillOnce(Return(0.5));
882+
EXPECT_CALL(m_engineMock, requestRedraw()).WillRepeatedly(Return());
883+
code->run(ctx.get());
884+
ASSERT_FALSE(code->isFinished(ctx.get()));
885+
ASSERT_EQ(std::round(sprite->x() * 100) / 100, 29.98);
886+
ASSERT_EQ(std::round(sprite->y() * 100) / 100, 4.25);
887+
888+
EXPECT_CALL(timer, elapsedTime()).WillOnce(Return(1.75));
889+
EXPECT_CALL(m_engineMock, requestRedraw()).WillRepeatedly(Return());
890+
code->run(ctx.get());
891+
ASSERT_FALSE(code->isFinished(ctx.get()));
892+
ASSERT_EQ(std::round(sprite->x() * 100) / 100, -23.26);
893+
ASSERT_EQ(std::round(sprite->y() * 100) / 100, 16.13);
894+
895+
EXPECT_CALL(timer, elapsedTime()).WillOnce(Return(2.55));
896+
EXPECT_CALL(m_engineMock, requestRedraw()).WillRepeatedly(Return());
897+
code->run(ctx.get());
898+
ASSERT_TRUE(code->isFinished(ctx.get()));
899+
ASSERT_EQ(sprite->x(), -55.2);
900+
ASSERT_EQ(sprite->y(), 23.254);
901+
}
902+
903+
{
904+
auto stage = std::make_shared<Stage>();
905+
ScriptBuilder builder(m_extension.get(), m_engine, stage);
906+
907+
builder.addBlock("motion_glidesecstoxy");
908+
builder.addValueInput("SECS", 2.5);
909+
builder.addValueInput("X", -55.2);
910+
builder.addValueInput("Y", 23.254);
911+
auto block = builder.currentBlock();
912+
913+
Compiler compiler(&m_engineMock, stage.get());
914+
auto code = compiler.compile(block);
915+
Script script(stage.get(), block, &m_engineMock);
916+
script.setCode(code);
917+
Thread thread(stage.get(), &m_engineMock, &script);
918+
auto ctx = code->createExecutionContext(&thread);
919+
StackTimerMock timer;
920+
ctx->setStackTimer(&timer);
921+
922+
EXPECT_CALL(timer, start(2.5));
923+
EXPECT_CALL(m_engineMock, requestRedraw()).WillRepeatedly(Return());
924+
code->run(ctx.get());
925+
ASSERT_FALSE(code->isFinished(ctx.get()));
926+
927+
EXPECT_CALL(timer, elapsedTime()).WillOnce(Return(0.5));
928+
EXPECT_CALL(m_engineMock, requestRedraw()).WillRepeatedly(Return());
929+
code->run(ctx.get());
930+
ASSERT_FALSE(code->isFinished(ctx.get()));
931+
932+
EXPECT_CALL(timer, elapsedTime()).WillOnce(Return(1.75));
933+
EXPECT_CALL(m_engineMock, requestRedraw()).WillRepeatedly(Return());
934+
code->run(ctx.get());
935+
ASSERT_FALSE(code->isFinished(ctx.get()));
936+
937+
EXPECT_CALL(timer, elapsedTime()).WillOnce(Return(2.55));
938+
EXPECT_CALL(m_engineMock, requestRedraw()).WillRepeatedly(Return());
939+
code->run(ctx.get());
940+
ASSERT_TRUE(code->isFinished(ctx.get()));
941+
}
942+
}

0 commit comments

Comments
 (0)