Ghost flag not sync between multiple simultaneous overlap event fire


Recently I’am trying to bring students who are familiar with single threading programming environment to the multithreading world. Multiple event firing seems natural for those who have Scratch experience, while some may be confused with the implicit yielding in the event blocks.

The following project shows the common way students try to implement a ‘invincible time’ after touching a enemy

A button creates an enemy, B button moves player to enemy.

The code works fine in single enemy, but fails if touching multiple enemies simultaneously (A button twice then B button), because multiple overlap events are fired in the same tick even though ghost mode set on.

To my understanding the implicit yielding in pause(500) and no ghost flag checking before overlap callback invocation together is the explanation, but I find it too much for students (age 10-11) understanding the whole multithreading model (non-preemptive, synchronization, etc.)

Currently a block is introduced to mask the complication.

Or shall we just introduce the complication of processing sprite collision events in one tick in one snapshot all together to the students?

1 Like

To confirm, you’re suggesting a check around this line here that skips the event handler if either sprite is now a ghost?

That sounds reasonable to me - I guess it makes the order in which the events are registered / potentially result in behavioral changes, but that’s not unreasonable.

Woah, thanks for the quick reply.

I’m reading that line too, and it suddenly came to me that what if they are not just setting the ghost flag but tried to bounce some sprite(changing the position), which would break the whole runInParallel sprite collision handling.

Still have no idea how to simplify things for the kids.

Yeah, that’s fair. I’m thinking about it and I think bailing out there is the correct behavior; need to play around with it for a second to make sure I’m not forgetting something obvious.

And yeah, when it matters how the async code behaves, it becomes really hard to grok for new coders; I’m not certain on the correct way to teach / simplify it either :frowning:

But also re: your block, I was thinking a while ago that we might need a set {flag} {on/off} for {500} ms block (like the one you have, but for any flag - if you want to try it should ‘just work’ if you add a param for the flag to the block and make sure it’s set as the SpriteFlag type); would be super helpful for things like this.

Edit: @felixtsu in case you’re up for testing it, here’s a build with that change (admittedly I mainly just felt like testing making an extra build)

Will try to explains that again in the coming weekend with some unplugged activities, hope will give them some straightforward demonstration of concurrency.

Speaking of that block, I’m stuck at one issue. The implementation is to wrap(AOP) overlaps event handlers for a period of time and then unwrap them. But not able to intercept sprite.overlapsWith() (turns out typescript is not javascript, can’t intercept instance methods, lol), any suggestion on this?

It works!

Ahh, to be fair that’s a ‘MakeCode TypeScript is not like javascript’ part - we’re a subset of TypeScript, which is a superset of JavaScript (see

and ahh, I had misunderstood it – I was assuming it was just a wrapper around a delayed setting of the flag, have to read it. Not sure that’s going to be something that’s supported right away. You can try something like: Making my own block that has a body and is not a top block that wraps the blocks in the overlap?

Oops, I missed one thing, ‘Invincible’ is a little bit different from GhostMode. In the conceptual level, an easy-understanding interpretation is when the player become invincible, the player sprite does not collide with other spites but still hits wall.

That’s the idea behind the implementation, to eat all overlaps event of the ‘invincible’ sprite.

There’s now two native entry points for sprite overlap event
sprites.onOverlap() and sprite.overlapsWith()

For sprite.onOverlap() the implementation use a stub to wrap overlapHandlers for a given time, unwrap afterwards.

But I have not work out the sprite.overlapsWith(), I thought it would be like a classic AOP scenario that we did for logging or auth checking

let originialOverlapsWithFunction = sprite.overlapsWith;
sprite.overlapsWith = function() {return; }
// ... after some time
sprite.overlapsWith = originialOverlapsWithFunction;

Then I realize that javascript type OOP is not supported, typescript is some-what Class Oriented :weary: :weary: