Skip to content

Commit 070bda4

Browse files
authored
Merge pull request #442 from scratchcpp/spritemodel_onmoved
Set sprite position using a single function call
2 parents d7e05e2 + fdff24c commit 070bda4

File tree

8 files changed

+100
-47
lines changed

8 files changed

+100
-47
lines changed

include/scratchcpp/ispritehandler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ class LIBSCRATCHCPP_EXPORT ISpriteHandler
3535
/*! Called when the Y-coordinate changes. */
3636
virtual void onYChanged(double y) = 0;
3737

38+
/*! Called when the sprite position changes. */
39+
virtual void onMoved(double oldX, double oldY, double newX, double newY) = 0;
40+
3841
/*! Called when the size changes. */
3942
virtual void onSizeChanged(double size) = 0;
4043

include/scratchcpp/sprite.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ class LIBSCRATCHCPP_EXPORT Sprite
4747
double y() const;
4848
void setY(double newY);
4949

50+
void setPosition(double x, double y);
51+
5052
double size() const;
5153
void setSize(double newSize);
5254

src/blocks/motionblocks.cpp

Lines changed: 19 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,7 @@ unsigned int MotionBlocks::moveSteps(VirtualMachine *vm)
275275
if (sprite) {
276276
double dir = sprite->direction();
277277
double steps = vm->getInput(0, 1)->toDouble();
278-
sprite->setX(sprite->x() + std::sin(dir * pi / 180) * steps);
279-
sprite->setY(sprite->y() + std::cos(dir * pi / 180) * steps);
278+
sprite->setPosition(sprite->x() + std::sin(dir * pi / 180) * steps, sprite->y() + std::cos(dir * pi / 180) * steps);
280279
}
281280

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

394393
if (sprite) {
395-
sprite->setX(vm->getInput(0, 2)->toDouble());
396-
sprite->setY(vm->getInput(1, 2)->toDouble());
394+
sprite->setPosition(vm->getInput(0, 2)->toDouble(), vm->getInput(1, 2)->toDouble());
397395
}
398396

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

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

411-
if (value == "_mouse_") {
412-
sprite->setX(vm->engine()->mouseX());
413-
sprite->setY(vm->engine()->mouseY());
414-
} else if (value == "_random_") {
409+
if (value == "_mouse_")
410+
sprite->setPosition(vm->engine()->mouseX(), vm->engine()->mouseY());
411+
else if (value == "_random_") {
415412
const unsigned int stageWidth = vm->engine()->stageWidth();
416413
const unsigned int stageHeight = vm->engine()->stageHeight();
417414

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

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

427-
if (targetSprite) {
428-
sprite->setX(targetSprite->x());
429-
sprite->setY(targetSprite->y());
430-
}
423+
if (targetSprite)
424+
sprite->setPosition(targetSprite->x(), targetSprite->y());
431425
}
432426

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

442-
if (sprite && targetSprite) {
443-
sprite->setX(targetSprite->x());
444-
sprite->setY(targetSprite->y());
445-
}
436+
if (sprite && targetSprite)
437+
sprite->setPosition(targetSprite->x(), targetSprite->y());
446438

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

454-
if (sprite) {
455-
sprite->setX(vm->engine()->mouseX());
456-
sprite->setY(vm->engine()->mouseY());
457-
}
446+
if (sprite)
447+
sprite->setPosition(vm->engine()->mouseX(), vm->engine()->mouseY());
458448

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

473-
sprite->setX(rng->randint(-static_cast<int>(stageWidth / 2), stageWidth / 2));
474-
sprite->setY(rng->randint(-static_cast<int>(stageHeight / 2), stageHeight / 2));
463+
sprite->setPosition(rng->randint(-static_cast<int>(stageWidth / 2), stageWidth / 2), rng->randint(-static_cast<int>(stageHeight / 2), stageHeight / 2));
475464
}
476465

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

487476
if (secs <= 0) {
488-
if (sprite) {
489-
sprite->setX(x);
490-
sprite->setY(y);
491-
}
477+
if (sprite)
478+
sprite->setPosition(x, y);
492479

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

518505
if (elapsedTime >= maxTime) {
519-
if (sprite) {
520-
sprite->setX(x);
521-
sprite->setY(y);
522-
}
506+
if (sprite)
507+
sprite->setPosition(x, y);
523508

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

533-
sprite->setX(startX + (x - startX) * factor);
534-
sprite->setY(startY + (y - startY) * factor);
518+
sprite->setPosition(startX + (x - startX) * factor, startY + (y - startY) * factor);
535519
}
536520

537521
vm->stop(true, true, true);
@@ -750,8 +734,7 @@ unsigned int MotionBlocks::ifOnEdgeBounce(VirtualMachine *vm)
750734
// Keep within the stage
751735
double fencedX, fencedY;
752736
sprite->keepInFence(sprite->x(), sprite->y(), &fencedX, &fencedY);
753-
sprite->setX(fencedX);
754-
sprite->setY(fencedY);
737+
sprite->setPosition(fencedX, fencedY);
755738

756739
return 0;
757740
}

src/scratch/sprite.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,17 @@ void Sprite::setY(double newY)
184184
impl->iface->onYChanged(impl->y);
185185
}
186186

187+
/* Sets the position of the sprite. */
188+
void Sprite::setPosition(double x, double y)
189+
{
190+
setXY(x, y);
191+
192+
if (impl->iface) {
193+
impl->iface->onXChanged(impl->x);
194+
impl->iface->onYChanged(impl->y);
195+
}
196+
}
197+
187198
/*! Returns the size. */
188199
double Sprite::size() const
189200
{
@@ -421,6 +432,9 @@ void Sprite::setXY(double x, double y)
421432
{
422433
IEngine *eng = engine();
423434

435+
double oldX = impl->x;
436+
double oldY = impl->y;
437+
424438
if (eng && !eng->spriteFencingEnabled()) {
425439
impl->x = x;
426440
impl->y = y;
@@ -433,4 +447,7 @@ void Sprite::setXY(double x, double y)
433447
if (eng)
434448
eng->requestRedraw();
435449
}
450+
451+
if (impl->iface)
452+
impl->iface->onMoved(oldX, oldY, impl->x, impl->y);
436453
}

test/blocks/motion_blocks_test.cpp

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,12 +1132,13 @@ TEST_F(MotionBlocksTest, IfOnEdgeBounceImpl)
11321132
vm.setBytecode(bytecode);
11331133
vm.setFunctions(functions);
11341134

1135-
EXPECT_CALL(m_engineMock, stageWidth()).Times(9).WillRepeatedly(Return(480));
1136-
EXPECT_CALL(m_engineMock, stageHeight()).Times(9).WillRepeatedly(Return(360));
1135+
EXPECT_CALL(m_engineMock, stageWidth()).WillRepeatedly(Return(480));
1136+
EXPECT_CALL(m_engineMock, stageHeight()).WillRepeatedly(Return(360));
11371137

11381138
// No edge
11391139
EXPECT_CALL(m_engineMock, requestRedraw()).Times(3);
11401140
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(2).WillRepeatedly(Return(false));
1141+
EXPECT_CALL(handler, onMoved).Times(2);
11411142
EXPECT_CALL(handler, onXChanged);
11421143
EXPECT_CALL(handler, onYChanged);
11431144
EXPECT_CALL(handler, onDirectionChanged);
@@ -1153,8 +1154,9 @@ TEST_F(MotionBlocksTest, IfOnEdgeBounceImpl)
11531154
ASSERT_EQ(sprite.direction(), -45);
11541155

11551156
// Left edge
1156-
EXPECT_CALL(m_engineMock, requestRedraw()).Times(5);
1157-
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(4).WillRepeatedly(Return(false));
1157+
EXPECT_CALL(m_engineMock, requestRedraw()).Times(4);
1158+
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(3).WillRepeatedly(Return(false));
1159+
EXPECT_CALL(handler, onMoved).Times(3);
11581160
EXPECT_CALL(handler, onXChanged).Times(2);
11591161
EXPECT_CALL(handler, onYChanged).Times(2);
11601162
EXPECT_CALL(handler, onDirectionChanged);
@@ -1170,8 +1172,9 @@ TEST_F(MotionBlocksTest, IfOnEdgeBounceImpl)
11701172
ASSERT_EQ(std::round(sprite.direction() * 100) / 100, 45);
11711173

11721174
// Top edge
1173-
EXPECT_CALL(m_engineMock, requestRedraw()).Times(6);
1174-
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(4).WillRepeatedly(Return(false));
1175+
EXPECT_CALL(m_engineMock, requestRedraw()).Times(5);
1176+
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(3).WillRepeatedly(Return(false));
1177+
EXPECT_CALL(handler, onMoved).Times(3);
11751178
EXPECT_CALL(handler, onXChanged).Times(2);
11761179
EXPECT_CALL(handler, onYChanged).Times(2);
11771180
EXPECT_CALL(handler, onDirectionChanged).Times(2);
@@ -1188,8 +1191,9 @@ TEST_F(MotionBlocksTest, IfOnEdgeBounceImpl)
11881191
ASSERT_EQ(sprite.direction(), 135);
11891192

11901193
// Right edge
1191-
EXPECT_CALL(m_engineMock, requestRedraw()).Times(5);
1192-
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(4).WillRepeatedly(Return(false));
1194+
EXPECT_CALL(m_engineMock, requestRedraw()).Times(4);
1195+
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(3).WillRepeatedly(Return(false));
1196+
EXPECT_CALL(handler, onMoved).Times(3);
11931197
EXPECT_CALL(handler, onXChanged).Times(2);
11941198
EXPECT_CALL(handler, onYChanged).Times(2);
11951199
EXPECT_CALL(handler, onDirectionChanged);
@@ -1205,8 +1209,9 @@ TEST_F(MotionBlocksTest, IfOnEdgeBounceImpl)
12051209
ASSERT_EQ(sprite.direction(), -135);
12061210

12071211
// Bottom edge
1208-
EXPECT_CALL(m_engineMock, requestRedraw()).Times(5);
1209-
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(4).WillRepeatedly(Return(false));
1212+
EXPECT_CALL(m_engineMock, requestRedraw()).Times(4);
1213+
EXPECT_CALL(m_engineMock, spriteFencingEnabled()).Times(3).WillRepeatedly(Return(false));
1214+
EXPECT_CALL(handler, onMoved).Times(3);
12101215
EXPECT_CALL(handler, onXChanged).Times(2);
12111216
EXPECT_CALL(handler, onYChanged).Times(2);
12121217
EXPECT_CALL(handler, onDirectionChanged);

test/mocks/spritehandlermock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class SpriteHandlerMock : public ISpriteHandler
1818
MOCK_METHOD(void, onVisibleChanged, (bool), (override));
1919
MOCK_METHOD(void, onXChanged, (double), (override));
2020
MOCK_METHOD(void, onYChanged, (double), (override));
21+
MOCK_METHOD(void, onMoved, (double, double, double, double), (override));
2122
MOCK_METHOD(void, onSizeChanged, (double), (override));
2223
MOCK_METHOD(void, onDirectionChanged, (double), (override));
2324
MOCK_METHOD(void, onRotationStyleChanged, (Sprite::RotationStyle), (override));

test/scratch_classes/sprite_test.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ TEST(SpriteTest, XY)
233233

234234
EngineMock engine;
235235
sprite.setEngine(&engine);
236-
EXPECT_CALL(engine, requestRedraw()).Times(17);
236+
EXPECT_CALL(engine, requestRedraw()).Times(18);
237237
EXPECT_CALL(engine, spriteFencingEnabled()).Times(4).WillRepeatedly(Return(false));
238238

239239
sprite.setX(-53.25);
@@ -261,6 +261,7 @@ TEST(SpriteTest, XY)
261261
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
262262
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
263263
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
264+
EXPECT_CALL(handler, onMoved);
264265
EXPECT_CALL(handler, onXChanged);
265266
sprite.setX(319);
266267
ASSERT_EQ(sprite.x(), 319);
@@ -269,6 +270,7 @@ TEST(SpriteTest, XY)
269270
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
270271
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
271272
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
273+
EXPECT_CALL(handler, onMoved);
272274
EXPECT_CALL(handler, onXChanged);
273275
sprite.setX(75);
274276
ASSERT_EQ(sprite.x(), 75);
@@ -277,11 +279,13 @@ TEST(SpriteTest, XY)
277279
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
278280
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
279281
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
282+
EXPECT_CALL(handler, onMoved);
280283
EXPECT_CALL(handler, onXChanged);
281284
sprite.setX(400);
282285
ASSERT_EQ(sprite.x(), 344);
283286

284287
EXPECT_CALL(engine, spriteFencingEnabled()).WillOnce(Return(false));
288+
EXPECT_CALL(handler, onMoved);
285289
EXPECT_CALL(handler, onXChanged);
286290
sprite.setX(400);
287291
ASSERT_EQ(sprite.x(), 400);
@@ -290,11 +294,13 @@ TEST(SpriteTest, XY)
290294
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
291295
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
292296
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
297+
EXPECT_CALL(handler, onMoved);
293298
EXPECT_CALL(handler, onXChanged);
294299
sprite.setX(-400);
295300
ASSERT_EQ(sprite.x(), 155);
296301

297302
EXPECT_CALL(engine, spriteFencingEnabled()).WillOnce(Return(false));
303+
EXPECT_CALL(handler, onMoved);
298304
EXPECT_CALL(handler, onXChanged);
299305
sprite.setX(-400);
300306
ASSERT_EQ(sprite.x(), -400);
@@ -303,6 +309,7 @@ TEST(SpriteTest, XY)
303309
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
304310
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
305311
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
312+
EXPECT_CALL(handler, onMoved);
306313
EXPECT_CALL(handler, onYChanged);
307314
sprite.setY(150);
308315
ASSERT_EQ(sprite.y(), 150);
@@ -311,6 +318,7 @@ TEST(SpriteTest, XY)
311318
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
312319
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
313320
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
321+
EXPECT_CALL(handler, onMoved);
314322
EXPECT_CALL(handler, onYChanged);
315323
sprite.setY(-103);
316324
ASSERT_EQ(sprite.y(), -103);
@@ -319,11 +327,13 @@ TEST(SpriteTest, XY)
319327
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
320328
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
321329
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
330+
EXPECT_CALL(handler, onMoved);
322331
EXPECT_CALL(handler, onYChanged);
323332
sprite.setY(340);
324333
ASSERT_EQ(sprite.y(), 62);
325334

326335
EXPECT_CALL(engine, spriteFencingEnabled()).WillOnce(Return(false));
336+
EXPECT_CALL(handler, onMoved);
327337
EXPECT_CALL(handler, onYChanged);
328338
sprite.setY(340);
329339
ASSERT_EQ(sprite.y(), 340);
@@ -332,14 +342,24 @@ TEST(SpriteTest, XY)
332342
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
333343
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
334344
EXPECT_CALL(handler, boundingRect()).WillOnce(Return(rect));
345+
EXPECT_CALL(handler, onMoved);
335346
EXPECT_CALL(handler, onYChanged);
336347
sprite.setY(-340);
337348
ASSERT_EQ(sprite.y(), 86);
338349

339350
EXPECT_CALL(engine, spriteFencingEnabled()).WillOnce(Return(false));
351+
EXPECT_CALL(handler, onMoved);
340352
EXPECT_CALL(handler, onYChanged);
341353
sprite.setY(-340);
342354
ASSERT_EQ(sprite.y(), -340);
355+
356+
EXPECT_CALL(engine, spriteFencingEnabled()).WillOnce(Return(false));
357+
EXPECT_CALL(handler, onMoved);
358+
EXPECT_CALL(handler, onXChanged);
359+
EXPECT_CALL(handler, onYChanged);
360+
sprite.setPosition(56, -23);
361+
ASSERT_EQ(sprite.x(), 56);
362+
ASSERT_EQ(sprite.y(), -23);
343363
}
344364

345365
TEST(SpriteTest, Size)
@@ -525,6 +545,7 @@ TEST(SpriteTest, KeepInFence)
525545

526546
EXPECT_CALL(engine, requestRedraw()).Times(2);
527547
EXPECT_CALL(engine, spriteFencingEnabled()).Times(2).WillRepeatedly(Return(false));
548+
EXPECT_CALL(handler, onMoved).Times(2);
528549
EXPECT_CALL(handler, onXChanged);
529550
EXPECT_CALL(handler, onYChanged);
530551
sprite.setX(100);

0 commit comments

Comments
 (0)