Collision modes combination doesn't work as expected


#1

Maybe you remember the old game called Sokoban, I’ve created a simplified clone of it at https://studio.code.org/projects/gamelab/mt0-87v53EOli4Zx5wFzAA4F6p8ZpLp8shuoHto8S-s

The goal for the main character (player) is to push all flowers to their place (marked by bumps). The player should be able push ONLY ONE item at time and neither the player nor the pushed items should be able to get over the obstacles (trees).

I hoped to achieve the above by using the following statements in the draw() loop:

player.collide(obstacles); // 1. player can’t push obstacles
items.collide(obstacles); // 2. items can’t either
player.displace(items); // 3. player can push items
items.collide(items); // 4. item can’t push other items => player can push only 1 item

What I’ve observed however is, that points 2. and 4. are not working as expected:

A. Items, when pushed, can go over obstacles - try to push a flower towards a tree

B. More than one item is allowed to be pushed by the player, player even may overlap an item - try to push 2 or 3 flowers to see for yourself.

Is this behavior by design? If so please could you explain the sprite interaction “philosophy” somehow deeper in the help texts?

Or is this a bug which should be fixed?


#2

This is a really ambitious project, and it looks like a lot of fun. There are a few things going on that might be causing problems.

The first is that it doesn’t make sense for the items group to collide with itself. The collide method implies that the target sprite is blocking or moving something and the sprite that calls the method will be moved or blocked by it. When the same group is both calling the method and the target of it, it’s not clear which sprite will be the mover/blocker and which will be the moved/blocked.

The other is that it’s hard for the system to do chain reactions in the way that you want them done because the player and the item have already interacted when the item gets pushed into and interacts with the next item or obstacle, and there is no way in the system to “pass back” the interaction back into the player.

You can get around this in two ways. First use a callback function with your displace call that specifies that the sprite that the player has displaced is the one that will be calling collide, and any other item or obstacle sprites should be the target (mover/blocker) of the collide method. Second, add a line in the callback function that will have the player collide with the item it just displaced. That will push the player back to where it started. Here’s what the callback function could look like:

function extraCollide(originalCaller, originalTarget) {
  if ( originalTarget.collide(items)) {
      player.collide(items);
  }
  if ( originalTarget.collide(obstacles)) {
      player.collide(items);
  }
}

You can see an example of this in action in a remix: https://studio.code.org/projects/gamelab/oG1ZoddFQITj7OQh6UOg70CzjyI9Lfi_n-FiVewtza0/edit


#3

Wow thank you! The quality of your answer is certainly a way above I’ve expected form a non-commercial site!

You’ve not just corrected my bugs but also revealed by your example that collision related functions like collide(), displace() and such, can have a callback as a second parameter, an that callback receives the caller and target sprites. What more I can ask for? I was able to fix my code in no time, and now the playable version of my “sokoban” is published at:

I’ve created my first ever code.org classroom section this September and the intention of this project is to motivate my newbie students by showcasing it: “Look, what is possible to create by GameLab!”

A last question: is there some insider help we can learn about such useful secrets as those callbacks? IMO those are not mentioned on the help pages.

Thank you very much again and keep up the fantastic work on code.org.


#4

Hi! I’m so glad that was helpful to you. Game Lab is based off the p5.play library, so I just googled “p5.play collide” to see what I could find about the callback functions, thinking that would be the easiest way to do it without rewriting a bunch of inbuilt functionality. As far as I know, the help pages only include things that were consciously included in Game Lab, and not really those things that were grandfathered in through p5.play or Javascript. Someone else on the team might have a better understanding of how all of those things fit together.

If you really want to dig in, you can visit the GitHub pages, but I know that’s not as accessible as real documentation.

Also, I love your game!

Elizabeth