Skip to content

Set sprite position using a single function call #442

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/scratchcpp/ispritehandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class LIBSCRATCHCPP_EXPORT ISpriteHandler
/*! Called when the Y-coordinate changes. */
virtual void onYChanged(double y) = 0;

/*! Called when the sprite position changes. */
virtual void onMoved(double oldX, double oldY, double newX, double newY) = 0;

/*! Called when the size changes. */
virtual void onSizeChanged(double size) = 0;

Expand Down
2 changes: 2 additions & 0 deletions include/scratchcpp/sprite.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class LIBSCRATCHCPP_EXPORT Sprite
double y() const;
void setY(double newY);

void setPosition(double x, double y);

double size() const;
void setSize(double newSize);

Expand Down
55 changes: 19 additions & 36 deletions src/blocks/motionblocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,7 @@ unsigned int MotionBlocks::moveSteps(VirtualMachine *vm)
if (sprite) {
double dir = sprite->direction();
double steps = vm->getInput(0, 1)->toDouble();
sprite->setX(sprite->x() + std::sin(dir * pi / 180) * steps);
sprite->setY(sprite->y() + std::cos(dir * pi / 180) * steps);
sprite->setPosition(sprite->x() + std::sin(dir * pi / 180) * steps, sprite->y() + std::cos(dir * pi / 180) * steps);
}

return 1;
Expand Down Expand Up @@ -392,8 +391,7 @@ unsigned int MotionBlocks::goToXY(VirtualMachine *vm)
Sprite *sprite = dynamic_cast<Sprite *>(vm->target());

if (sprite) {
sprite->setX(vm->getInput(0, 2)->toDouble());
sprite->setY(vm->getInput(1, 2)->toDouble());
sprite->setPosition(vm->getInput(0, 2)->toDouble(), vm->getInput(1, 2)->toDouble());
}

return 2;
Expand All @@ -408,26 +406,22 @@ unsigned int MotionBlocks::goTo(VirtualMachine *vm)

std::string value = vm->getInput(0, 1)->toString();

if (value == "_mouse_") {
sprite->setX(vm->engine()->mouseX());
sprite->setY(vm->engine()->mouseY());
} else if (value == "_random_") {
if (value == "_mouse_")
sprite->setPosition(vm->engine()->mouseX(), vm->engine()->mouseY());
else if (value == "_random_") {
const unsigned int stageWidth = vm->engine()->stageWidth();
const unsigned int stageHeight = vm->engine()->stageHeight();

if (!rng)
rng = RandomGenerator::instance().get();

sprite->setX(rng->randint(-static_cast<int>(stageWidth / 2), stageWidth / 2));
sprite->setY(rng->randint(-static_cast<int>(stageHeight / 2), stageHeight / 2));
sprite->setPosition(rng->randint(-static_cast<int>(stageWidth / 2), stageWidth / 2), rng->randint(-static_cast<int>(stageHeight / 2), stageHeight / 2));
} else {
Target *target = vm->engine()->targetAt(vm->engine()->findTarget(value));
Sprite *targetSprite = dynamic_cast<Sprite *>(target);

if (targetSprite) {
sprite->setX(targetSprite->x());
sprite->setY(targetSprite->y());
}
if (targetSprite)
sprite->setPosition(targetSprite->x(), targetSprite->y());
}

return 1;
Expand All @@ -439,10 +433,8 @@ unsigned int MotionBlocks::goToByIndex(VirtualMachine *vm)
Target *target = vm->engine()->targetAt(vm->getInput(0, 1)->toInt());
Sprite *targetSprite = dynamic_cast<Sprite *>(target);

if (sprite && targetSprite) {
sprite->setX(targetSprite->x());
sprite->setY(targetSprite->y());
}
if (sprite && targetSprite)
sprite->setPosition(targetSprite->x(), targetSprite->y());

return 1;
}
Expand All @@ -451,10 +443,8 @@ unsigned int MotionBlocks::goToMousePointer(VirtualMachine *vm)
{
Sprite *sprite = dynamic_cast<Sprite *>(vm->target());

if (sprite) {
sprite->setX(vm->engine()->mouseX());
sprite->setY(vm->engine()->mouseY());
}
if (sprite)
sprite->setPosition(vm->engine()->mouseX(), vm->engine()->mouseY());

return 0;
}
Expand All @@ -470,8 +460,7 @@ unsigned int MotionBlocks::goToRandomPosition(VirtualMachine *vm)
if (!rng)
rng = RandomGenerator::instance().get();

sprite->setX(rng->randint(-static_cast<int>(stageWidth / 2), stageWidth / 2));
sprite->setY(rng->randint(-static_cast<int>(stageHeight / 2), stageHeight / 2));
sprite->setPosition(rng->randint(-static_cast<int>(stageWidth / 2), stageWidth / 2), rng->randint(-static_cast<int>(stageHeight / 2), stageHeight / 2));
}

return 0;
Expand All @@ -485,10 +474,8 @@ void MotionBlocks::startGlidingToPos(VirtualMachine *vm, double x, double y, dou
return;

if (secs <= 0) {
if (sprite) {
sprite->setX(x);
sprite->setY(y);
}
if (sprite)
sprite->setPosition(x, y);

return;
}
Expand Down Expand Up @@ -516,10 +503,8 @@ void MotionBlocks::continueGliding(VirtualMachine *vm)
double y = m_glideMap[vm].second.second;

if (elapsedTime >= maxTime) {
if (sprite) {
sprite->setX(x);
sprite->setY(y);
}
if (sprite)
sprite->setPosition(x, y);

m_timeMap.erase(vm);
m_glideMap.erase(vm);
Expand All @@ -530,8 +515,7 @@ void MotionBlocks::continueGliding(VirtualMachine *vm)
double factor = elapsedTime / static_cast<double>(maxTime);
assert(factor >= 0 && factor < 1);

sprite->setX(startX + (x - startX) * factor);
sprite->setY(startY + (y - startY) * factor);
sprite->setPosition(startX + (x - startX) * factor, startY + (y - startY) * factor);
}

vm->stop(true, true, true);
Expand Down Expand Up @@ -750,8 +734,7 @@ unsigned int MotionBlocks::ifOnEdgeBounce(VirtualMachine *vm)
// Keep within the stage
double fencedX, fencedY;
sprite->keepInFence(sprite->x(), sprite->y(), &fencedX, &fencedY);
sprite->setX(fencedX);
sprite->setY(fencedY);
sprite->setPosition(fencedX, fencedY);

return 0;
}
Expand Down
17 changes: 17 additions & 0 deletions src/scratch/sprite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,17 @@ void Sprite::setY(double newY)
impl->iface->onYChanged(impl->y);
}

/* Sets the position of the sprite. */
void Sprite::setPosition(double x, double y)
{
setXY(x, y);

if (impl->iface) {
impl->iface->onXChanged(impl->x);
impl->iface->onYChanged(impl->y);
}
}

/*! Returns the size. */
double Sprite::size() const
{
Expand Down Expand Up @@ -421,6 +432,9 @@ void Sprite::setXY(double x, double y)
{
IEngine *eng = engine();

double oldX = impl->x;
double oldY = impl->y;

if (eng && !eng->spriteFencingEnabled()) {
impl->x = x;
impl->y = y;
Expand All @@ -433,4 +447,7 @@ void Sprite::setXY(double x, double y)
if (eng)
eng->requestRedraw();
}

if (impl->iface)
impl->iface->onMoved(oldX, oldY, impl->x, impl->y);
}
25 changes: 15 additions & 10 deletions test/blocks/motion_blocks_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1132,12 +1132,13 @@ TEST_F(MotionBlocksTest, IfOnEdgeBounceImpl)
vm.setBytecode(bytecode);
vm.setFunctions(functions);

EXPECT_CALL(m_engineMock, stageWidth()).Times(9).WillRepeatedly(Return(480));
EXPECT_CALL(m_engineMock, stageHeight()).Times(9).WillRepeatedly(Return(360));
EXPECT_CALL(m_engineMock, stageWidth()).WillRepeatedly(Return(480));
EXPECT_CALL(m_engineMock, stageHeight()).WillRepeatedly(Return(360));

// No edge
EXPECT_CALL(m_engineMock, requestRedraw()).Times(3);
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(2).WillRepeatedly(Return(false));
EXPECT_CALL(handler, onMoved).Times(2);
EXPECT_CALL(handler, onXChanged);
EXPECT_CALL(handler, onYChanged);
EXPECT_CALL(handler, onDirectionChanged);
Expand All @@ -1153,8 +1154,9 @@ TEST_F(MotionBlocksTest, IfOnEdgeBounceImpl)
ASSERT_EQ(sprite.direction(), -45);

// Left edge
EXPECT_CALL(m_engineMock, requestRedraw()).Times(5);
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(4).WillRepeatedly(Return(false));
EXPECT_CALL(m_engineMock, requestRedraw()).Times(4);
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(3).WillRepeatedly(Return(false));
EXPECT_CALL(handler, onMoved).Times(3);
EXPECT_CALL(handler, onXChanged).Times(2);
EXPECT_CALL(handler, onYChanged).Times(2);
EXPECT_CALL(handler, onDirectionChanged);
Expand All @@ -1170,8 +1172,9 @@ TEST_F(MotionBlocksTest, IfOnEdgeBounceImpl)
ASSERT_EQ(std::round(sprite.direction() * 100) / 100, 45);

// Top edge
EXPECT_CALL(m_engineMock, requestRedraw()).Times(6);
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(4).WillRepeatedly(Return(false));
EXPECT_CALL(m_engineMock, requestRedraw()).Times(5);
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(3).WillRepeatedly(Return(false));
EXPECT_CALL(handler, onMoved).Times(3);
EXPECT_CALL(handler, onXChanged).Times(2);
EXPECT_CALL(handler, onYChanged).Times(2);
EXPECT_CALL(handler, onDirectionChanged).Times(2);
Expand All @@ -1188,8 +1191,9 @@ TEST_F(MotionBlocksTest, IfOnEdgeBounceImpl)
ASSERT_EQ(sprite.direction(), 135);

// Right edge
EXPECT_CALL(m_engineMock, requestRedraw()).Times(5);
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(4).WillRepeatedly(Return(false));
EXPECT_CALL(m_engineMock, requestRedraw()).Times(4);
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(3).WillRepeatedly(Return(false));
EXPECT_CALL(handler, onMoved).Times(3);
EXPECT_CALL(handler, onXChanged).Times(2);
EXPECT_CALL(handler, onYChanged).Times(2);
EXPECT_CALL(handler, onDirectionChanged);
Expand All @@ -1205,8 +1209,9 @@ TEST_F(MotionBlocksTest, IfOnEdgeBounceImpl)
ASSERT_EQ(sprite.direction(), -135);

// Bottom edge
EXPECT_CALL(m_engineMock, requestRedraw()).Times(5);
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(4).WillRepeatedly(Return(false));
EXPECT_CALL(m_engineMock, requestRedraw()).Times(4);
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(3).WillRepeatedly(Return(false));
EXPECT_CALL(handler, onMoved).Times(3);
EXPECT_CALL(handler, onXChanged).Times(2);
EXPECT_CALL(handler, onYChanged).Times(2);
EXPECT_CALL(handler, onDirectionChanged);
Expand Down
1 change: 1 addition & 0 deletions test/mocks/spritehandlermock.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class SpriteHandlerMock : public ISpriteHandler
MOCK_METHOD(void, onVisibleChanged, (bool), (override));
MOCK_METHOD(void, onXChanged, (double), (override));
MOCK_METHOD(void, onYChanged, (double), (override));
MOCK_METHOD(void, onMoved, (double, double, double, double), (override));
MOCK_METHOD(void, onSizeChanged, (double), (override));
MOCK_METHOD(void, onDirectionChanged, (double), (override));
MOCK_METHOD(void, onRotationStyleChanged, (Sprite::RotationStyle), (override));
Expand Down
23 changes: 22 additions & 1 deletion test/scratch_classes/sprite_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ TEST(SpriteTest, XY)

EngineMock engine;
sprite.setEngine(&engine);
EXPECT_CALL(engine, requestRedraw()).Times(17);
EXPECT_CALL(engine, requestRedraw()).Times(18);
EXPECT_CALL(engine, spriteFencingEnabled()).Times(4).WillRepeatedly(Return(false));

sprite.setX(-53.25);
Expand Down Expand Up @@ -261,6 +261,7 @@ TEST(SpriteTest, XY)
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
EXPECT_CALL(handler, onMoved);
EXPECT_CALL(handler, onXChanged);
sprite.setX(319);
ASSERT_EQ(sprite.x(), 319);
Expand All @@ -269,6 +270,7 @@ TEST(SpriteTest, XY)
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
EXPECT_CALL(handler, onMoved);
EXPECT_CALL(handler, onXChanged);
sprite.setX(75);
ASSERT_EQ(sprite.x(), 75);
Expand All @@ -277,11 +279,13 @@ TEST(SpriteTest, XY)
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
EXPECT_CALL(handler, onMoved);
EXPECT_CALL(handler, onXChanged);
sprite.setX(400);
ASSERT_EQ(sprite.x(), 344);

EXPECT_CALL(engine, spriteFencingEnabled()).WillOnce(Return(false));
EXPECT_CALL(handler, onMoved);
EXPECT_CALL(handler, onXChanged);
sprite.setX(400);
ASSERT_EQ(sprite.x(), 400);
Expand All @@ -290,11 +294,13 @@ TEST(SpriteTest, XY)
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
EXPECT_CALL(handler, onMoved);
EXPECT_CALL(handler, onXChanged);
sprite.setX(-400);
ASSERT_EQ(sprite.x(), 155);

EXPECT_CALL(engine, spriteFencingEnabled()).WillOnce(Return(false));
EXPECT_CALL(handler, onMoved);
EXPECT_CALL(handler, onXChanged);
sprite.setX(-400);
ASSERT_EQ(sprite.x(), -400);
Expand All @@ -303,6 +309,7 @@ TEST(SpriteTest, XY)
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
EXPECT_CALL(handler, onMoved);
EXPECT_CALL(handler, onYChanged);
sprite.setY(150);
ASSERT_EQ(sprite.y(), 150);
Expand All @@ -311,6 +318,7 @@ TEST(SpriteTest, XY)
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
EXPECT_CALL(handler, onMoved);
EXPECT_CALL(handler, onYChanged);
sprite.setY(-103);
ASSERT_EQ(sprite.y(), -103);
Expand All @@ -319,11 +327,13 @@ TEST(SpriteTest, XY)
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
EXPECT_CALL(handler, onMoved);
EXPECT_CALL(handler, onYChanged);
sprite.setY(340);
ASSERT_EQ(sprite.y(), 62);

EXPECT_CALL(engine, spriteFencingEnabled()).WillOnce(Return(false));
EXPECT_CALL(handler, onMoved);
EXPECT_CALL(handler, onYChanged);
sprite.setY(340);
ASSERT_EQ(sprite.y(), 340);
Expand All @@ -332,14 +342,24 @@ TEST(SpriteTest, XY)
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
EXPECT_CALL(handler, onMoved);
EXPECT_CALL(handler, onYChanged);
sprite.setY(-340);
ASSERT_EQ(sprite.y(), 86);

EXPECT_CALL(engine, spriteFencingEnabled()).WillOnce(Return(false));
EXPECT_CALL(handler, onMoved);
EXPECT_CALL(handler, onYChanged);
sprite.setY(-340);
ASSERT_EQ(sprite.y(), -340);

EXPECT_CALL(engine, spriteFencingEnabled()).WillOnce(Return(false));
EXPECT_CALL(handler, onMoved);
EXPECT_CALL(handler, onXChanged);
EXPECT_CALL(handler, onYChanged);
sprite.setPosition(56, -23);
ASSERT_EQ(sprite.x(), 56);
ASSERT_EQ(sprite.y(), -23);
}

TEST(SpriteTest, Size)
Expand Down Expand Up @@ -525,6 +545,7 @@ TEST(SpriteTest, KeepInFence)

EXPECT_CALL(engine, requestRedraw()).Times(2);
EXPECT_CALL(engine, spriteFencingEnabled()).Times(2).WillRepeatedly(Return(false));
EXPECT_CALL(handler, onMoved).Times(2);
EXPECT_CALL(handler, onXChanged);
EXPECT_CALL(handler, onYChanged);
sprite.setX(100);
Expand Down
Loading