Discuss Scratch

frodewin
Scratcher
500+ posts

Set layer of sprites based on y position (absolute layering)

Problem statement: I have several sprites on screen, their layers should be set so that the sprite with the lowest position is in front, the next lowest behind it and so on. I know that layering them is easy when they are created in top to border order, but I'm specifically interested in sending the sprites to their layer after they have been created onto a random position (and probable just moved).

In the wiki, the following code is suggested to send a sprite to a specific layer:

gotofrontgobacknlayers

to set a sprite to a specific layer.

Ok, the “go to front” block is now a bit different in 3.0, but that is not the point. The problem is that this approach ist not working, because layers are not absolute, but relatively defined based on the other sprites. So, what we get it is not “go back (n) layers” but rather “go back (n) sprites behind you”.

I have no idea how I could efficiently sort sprites with this, I made a test program that generates 50 sprites and tries to layer them.

Press ‘1’ in the test program to generate 50 different sprites, the program then tries to layer them with the method described above. You see that most of the sprites are still not in the correct layer.

Press ‘2’ to get 50 sprites again, this time they are moving accross the screen. Layering algorithm from the wiki, not working.

In this project, they use a delay to sort the sprites. However, this creates flicker during the sorting process and is slow. It kinda works there because there are only around 5 sprites but even there you see a wrong layering every now and then.

Press ‘3’ in my project to see this delay method applied to the moving sprites. We see flicker and very low speed compared to scenario 2.

Any help how to solve the layer sorting is appreciated - best by remixing this project with a version that works. :-)
Anonymous1212144
Scratcher
100+ posts

Set layer of sprites based on y position (absolute layering)

Just use “go to front” on every sprite starting from the sprite you want to be in the very back to the sprite you want in the front.
frodewin
Scratcher
500+ posts

Set layer of sprites based on y position (absolute layering)

Anonymous1212144 wrote:

Just use “go to front” on every sprite starting from the sprite you want to be in the very back to the sprite you want in the front.

Thanks for the idea, but…

1. This creates flicker every time I execute this, because I woudl briefly sort the sprite in the very back to front, then the next one and so on. I have to execute this from time to time because the sprites could have moved.

2. I don't know a good way to make the sprites execute the go front in that order. Only way would be the delay method based on the y coordinate, but this creates a noticable delay (see this method applied Test Project when pressing 3)
deck26
Scratcher
1000+ posts

Set layer of sprites based on y position (absolute layering)

The problem is twofold - the way Scratch refers to layers and the order in which scripts run.

If you have 3 sprites and 50 clones you have 53 layers - one per object. Telling a clone to go back 100 layers because it has y value of 80 is no different to telling it to go back 52 layers since that is the maximum it can do.

But if a clone at 100 runs the script to go back 80 layers (so goes to the back) it is going behind any clone which has already run the script and most clones which run the script after it will end up behind it.

I've seen lots of project where the user thought telling one sprite to go back 1000 layers meant it must end up behind a sprite told to go back 500 layers but if the second sprite ran its script after the first it would still go behind.

I don't think you can do this other than by processing lists to manage the current layer numbers and then telling the clones to go to the front or rear in the correct order. Telling sprites 2, 3, 1 to go to front in that order would result in 1 in front of 3 in front of 2.
frodewin
Scratcher
500+ posts

Set layer of sprites based on y position (absolute layering)

deck26 wrote:

The problem is twofold - the way Scratch refers to layers and the order in which scripts run.

If you have 3 sprites and 50 clones you have 53 layers - one per object. Telling a clone to go back 100 layers because it has y value of 80 is no different to telling it to go back 52 layers since that is the maximum it can do.

But if a clone at 100 runs the script to go back 80 layers (so goes to the back) it is going behind any clone which has already run the script and most clones which run the script after it will end up behind it.

Very good formulation of the problem.

deck26 wrote:

I've seen lots of project where the user thought telling one sprite to go back 1000 layers meant it must end up behind a sprite told to go back 500 layers but if the second sprite ran its script after the first it would still go behind.

Which, in my opinion would have been the more natural behavior. I'm wondering why Scratch decided to handle layers as something relativ to other objects.

deck26 wrote:

I don't think you can do this other than by processing lists to manage the current layer numbers and then telling the clones to go to the front or rear in the correct order. Telling sprites 2, 3, 1 to go to front in that order would result in 1 in front of 3 in front of 2.

How would you implement that in the given example?
deck26
Scratcher
1000+ posts

Set layer of sprites based on y position (absolute layering)

Let's consider what you get when you press 1.

Give each clone a unique ID in the usual way (for this sprite only variable). As you create each clone you give add its y value to a list. You also create list containing the numbers 1 to 50. Now you sort the y-list and keep the correspondence with the second list. So if the lists contain

y number
180 1
150 2
100 3
200 4

and you wanted to sort by increasing y the number list would get sorted to 3, 2, 1, 4.

You then set a global variable ‘index’ to 1 and make a broadcast to the clones. In response to the broadcast each clone waits until item index of number list = cloneid. It then goes to front (or rear) and changes index by 1. So clone 3 would respond first, then clone 2 and so on.

For your option 1 that's it and the sort is only done once so you could try an insertion sort in a custom block with no screen refresh.

For the other options you'll need to sort the lists again every time there may be movement but the list will actually be close to being sorted so choosing the right sorting method is important for efficiency. If you're not aware of how sort method affects things you should probably do some research - it's an important issue in coding.

And that's your main problem - the time to sort the lists and for the clone to wait its turn may just be too much.

Last edited by deck26 (Jan. 31, 2019 11:28:44)

deck26
Scratcher
1000+ posts

Set layer of sprites based on y position (absolute layering)

https://scratch.mit.edu/projects/283464970/ handles option 1. I've put a delay between showing the clones and sorting the layers so you can see it happen.
deck26
Scratcher
1000+ posts

Set layer of sprites based on y position (absolute layering)

Got it working for option 2 as well! Not the smoothest but does work.
Anonymous1212144
Scratcher
100+ posts

Set layer of sprites based on y position (absolute layering)

You could also create a block that runs without screen refresh.
gor-dee
Scratcher
1000+ posts

Set layer of sprites based on y position (absolute layering)

It's an interesting problem, I had the same problem here https://scratch.mit.edu/projects/138934224/ but not with so many sprites!
A couple of thoughts…
If the sprites aren't touching it doesn't matter which layer they are on (I don't think this is going to help you with the number of sprites you have!)
Would pen or stamping be an option instead?
gor-dee
Scratcher
1000+ posts

Set layer of sprites based on y position (absolute layering)

I've had a go! https://scratch.mit.edu/projects/285824930/

Last edited by gor-dee (Feb. 11, 2019 01:42:52)

gor-dee_test
Scratcher
100+ posts

Set layer of sprites based on y position (absolute layering)

Hi, I don't know if you've seen my remix yet https://scratch.mit.edu/projects/285824930/
I was quite pleased how well it works and was trying some tweaks to improve it further when I realised it shouldn't work at all! It basically has a custom block running with screen refresh (in the stage) that has a repeat 480 loop in it. If this loop was running at 30 loops/sec it would slow all the movement down to 1 frame every 16secs but it doesn't. I remember Scratch 2.0 would execute loops faster than 30/sec if there was just a “change variable” inside and it appears 3.0 is the same, but if you set the custom block to run without refresh it breaks the project, so it seems that it yields to the wait blocks but all within one frame. Cool!
ItsRainingNans
Scratcher
19 posts

Set layer of sprites based on y position (absolute layering)

I've been trying to get some sort of sorting solution on this project and so far all the solutions I've seen haven't worked.

https://scratch.mit.edu/projects/793027339/

For now, I've just removed the sorting from it, as they all just broke it further.

All of the clones are stamped, so I'm pretty sure the solution would have to be something that stamps the highest clones first, and so on for the lower and lower ones. I can't figure out any ways to do this. I might have not fully understood gor-dee_test's solution so that MIGHT just be me not being smart enough to implement it into my project.

I have done sprite sorting in previous projects, but those solutions didn't seem to work in this either.
Deltawarrioir943
Scratcher
4 posts

Set layer of sprites based on y position (absolute layering)

I'm not sure if it to late or if you ever got it working, but if you haven't just check out Griffpatches tutorial at https://youtu.be/bxjbYJLAUYU, It helped me out so much I actually got chills XD

Powered by DjangoBB