Discuss Scratch

owlover2010
Scratcher
100+ posts

Scratch Workaround Guide VII

Why is a “mouse over report” detector disallowed? Or is this the wrong place to ask?
(mouse over [love v]:: sensing)
(mouse over [fave v]:: sensing)
(mouse over [report v])

Last edited by owlover2010 (March 23, 2023 06:14:06)

yavuz61035
Scratcher
500+ posts

Scratch Workaround Guide VII

owlover2010 wrote:

Why is a “mouse over report” detector disallowed? Or is this the wrong place to ask?
(mouse over [love v]:: sensing)
(mouse over [fave v]:: sensing)
(mouse over [report v])
qas would probably be better to ask in

but its disallowed because you could make it so you need to love and fave before playing a game or you could make it so if you reported you couldnt play the game
mumu245
Scratcher
1000+ posts

Scratch Workaround Guide VII

Could you pass me this topic? I would really like to maintain this kind of sticky!
5_g
Scratcher
1000+ posts

Scratch Workaround Guide VII

mumu245 wrote:

Could you pass me this topic? I would really like to maintain this kind of sticky!
wdym
medians
Scratcher
1000+ posts

Scratch Workaround Guide VII

mumu245 wrote:

Could you pass me this topic? I would really like to maintain this kind of sticky!
She is still maintaining it.
MSE666
Scratcher
26 posts

Scratch Workaround Guide VII

medians wrote:

(#165)

mumu245 wrote:

Could you pass me this topic? I would really like to maintain this kind of sticky!
She is still maintaining it.
nope
INSERT-USER_NAME
Scratcher
1000+ posts

Scratch Workaround Guide VII

MSE666 wrote:

medians wrote:

(#165)

mumu245 wrote:

Could you pass me this topic? I would really like to maintain this kind of sticky!
She is still maintaining it.
nope
uh, what?
_nix
Scratcher
1000+ posts

Scratch Workaround Guide VII

Nobody needs to argue over whether or not I'm maintaining this. I can answer for myself, so please don't feel the need to tell people that I am or am not maintaining.

Are other stickies this sought-after, I wonder…

Anyway, I haven't been keeping up with this as much as I'd like to. That's my fault. I'm gonna set aside at least one hour a week (generally on Friday or the weekend) where I check in with the guide and see what needs adding or updating. We'll see if that's something I can keep up for a while, and go from there, alright?

Last edited by _nix (March 31, 2023 19:51:10)

_nix
Scratcher
1000+ posts

Scratch Workaround Guide VII

10data10 wrote:

This may cross the line of being too complex for your guide but people are frequently asking about how to do this so it might help to have workarounds (or a few workarounds) included.
Thanks for the suggestion! Special information about clones was loosely on my radar, because there are a ton of workarounds and cool things you can do with clones and clone IDs. (I've used them a lot.) It's a more complicated subject, so I haven't really been sure how to fit it into the guide cleanly… And… I'm still not sure, but it's something I want to do! So I got started on writing the text, and I'll figure out the formatting to make it officially part of the guide later on, when more of it is done

Like I said, I'll come back to the thread once a week and fill in more. I'm going to edit this post with the work-in-progress, but keep in mind that it's a rough draft, so lots of stuff may change before it becomes properly part of the guide. (I'm thinking about posting it to another discussion topic, in Help with Scripts, or right at the top of a following discussion page here, because the first page is super super huge and really laggy to browse on older computers.)

Please heavens if you're going to quote this post, snip out everything below this line.

⎯⎯⎯ WIP content, here be dragons (last updated 4/7) ⎯⎯⎯

x position of clone, costume # of clone, etc

Scratch doesn't have any blocks for interacting with specific clones, but there are pretty simple workarounds for most blocks that might come in handy. They're all based on using a clone ID system. Every clone has its own ID, which is a “for this sprite only” variable that is a unique number for each clone. Clone data gets updated constantly in “for all sprites” lists, and accessed from those lists whenever needed.

This is a more complicated workaround, but once you learn how to use it, you'll have a very powerful tool for all kinds of projects involving clones!

The first step is to create “for all sprites” lists for each piece of information you'll want to track, like X position, Y position, direction, costume number, and so on. Make sure you delete all from each of these lists when the green flag is clicked, because restarting the project always deletes all clones, and you don't want any old data from the last time the project was run getting in the way.

when green flag clicked
delete all of [clone X v] :: list
delete all of [clone Y v] :: list
delete all of [clone direction v] :: list
delete all of [clone costume # v] :: list

Because the order Scratch evaluates blocks in the same frame can be hard to predict, you should use “wait 0 seconds” at the start of other “when flag pressed” scripts which are going to create clones.

Now you'll want to make a new custom block which replaces “create this clone”. Make a “for this sprite only” clone ID variable, too. The custom block will create a new clone, add the current information values to the list, and set the clone ID value to the length of the information lists.

when green flag clicked
set [clone ID v] to [0]

define create and track clone of myself
add (x position) to [clone X v]
add (y position) to [clone Y v]
add (direction) to [clone direction v]
add (costume [number v] :: looks) to [clone costume # v]
set [clone ID v] to (length of [clone X v])
create clone of [myself v]
set [clone ID v] to [0]

If you're going to have clones actually create clones of themselves, change the last part to restore the clone ID to its previous value instead of resetting it to zero. Use an additional “for this sprite only” variable:

define create and track clone of myself
... :: #c0c0c0
add (direction :: #8495dd) to [clone direction v] :: #d78c76
add (costume [number v] :: #a17edd) to [clone costume # v] :: #d78c76
add this: ({set [saved clone ID v] to (clone ID)} :: ring #f4f752) :: #4c97ff
set [clone ID v] to (length of [clone X v] :: #d78c76) :: #f19865
create clone of [myself v] :: #e7bd74
add this: ({set [clone ID v] to (saved clone ID)} :: ring #f4f752) :: cap #4c97ff

Next, you'll want to have each clone update the information in the “for all sprites” lists. You want this to happen every frame, so the latest information is always in the lists. A simple way is with a forever loop:

when I start as a clone
forever
replace item (clone ID) of [clone X v] with (x position)
replace item (clone ID) of [clone Y v] with (y position)
replace item (clone ID) of [clone direction v] with (direction)
replace item (clone ID) of [clone costume # v] with (costume [number v] :: looks)
end

If your project uses an “update” broadcast loop (such as “forever: broadcast update and wait” or “forever: broadcast tick and wait”), you can skip the forever loop and just put the “replace item” blocks at the bottom of the “when I receive update” script.

Now your project is good to go! If you run it, and show the clone information lists, it should automatically fill up with the details for each clone.

If you know the ID for a clone, you can get information about it by getting it from the lists. For example, ID 3 means that the third item of clone X, the third item of clone Y, the third item of clone direction, and so on, all are the information for that clone. Here's an example script:

when green flag clicked
wait (0) seconds :: control
create and track clone of myself :: custom
forever
set x to ((50) + (item (1) of [clone X v])
set y to ((50) + (item (1) of [clone Y v])
end

when I start as a clone
forever
glide (1) secs to [random position v] :: motion
end

The clone glides somewhere random, and the original sprite follows it.

for each of my clones

You can use a “for this sprite only” list, called “my clones”, to keep track of the clone ID for each clone that a sprite or clone creates of itself. Change the “create and track clone of myself” block to add the new clone ID to that list.

when green flag clicked :: #d4a47a
add this: ({delete all of [my clones v] :: list} :: ring #f4f752) :: #4c97ff
delete all of [clone X v] :: #d78c76
delete all of [clone Y v] :: #d78c76
... :: #c0c0c0

define create and track clone of myself
... :: #c0c0c0
set [saved clone ID v] to (clone ID :: #f19865) :: #f19865
set [clone ID v] to (length of [clone X v] :: #d78c76) :: #f19865
create clone of [myself v] :: #e7bd74
add this: ({add (clone ID) to [my clones v]} :: ring #f4f752) :: #4c97ff // Keep track of the new clone ID before restoring it.
set [clone ID v] to (saved clone ID :: #f19865) :: #f19865

when I start as a clone :: #e7bd74
add this: ({delete all of [my clones v] :: list} :: ring #f4f752) :: #4c97ff // The clone gets its own list of clones!
... :: #c0c0c0

Now you can loop over each item in the “my clones” list. Use a repeat loop or a “for” loop. (Look at the workaround for “for each item of list”, in Variables & Lists, for more information.)

set [index v] to [1]
repeat (length of [my clones v])
set [my clone's ID v] to (item (index) of [my clones v])
set [my clone's X v] to (item (my clone's ID) of [clone X v])
set [my clone's Y v] to (item (my clone's ID) of [clone Y v])
... do something interesting ... :: grey
change [index v] by (1)
end

clone that created me, parent ID

You might want a clone to be able to get information about the clone which created it! Track that information in the “create and track clone of” block:

define create and track clone of myself
... :: #c0c0c0
add this: ({set [saved parent ID v] to (parent ID)} :: ring #f4f752) :: #4c97ff // Like clone ID, we have to restore this when we're done.
set [saved clone ID v] to (clone ID :: #f19865) :: #f19865
add this: ({set [parent ID v] to (clone ID)} :: ring #f4f752) :: #4c97ff // Set parent ID to our own ID before getting a new ID for the new clone!
set [clone ID v] to (length of [clone X v] :: #d78c76) :: #f19865
create clone of [myself v] :: #e7bd74
add this: ({set [parent ID v] to (saved parent ID)} :: ring #f4f752) :: #4c97ff
set [clone ID v] to (saved clone ID :: #f19865) :: #f19865

(Alternate variable tracking which cuts out the need for “saved clone ID”, shout me out if you like assembly code)

define create and track clone of myself
... :: #c0c0c0
remove this: ({set [saved clone ID v] to (clone ID)} :: ring #321451) :: #FF661A
add this: ({
set [saved parent ID v] to (parent ID)
set [parent ID v] to (clone ID)
} :: ring #f4f752) :: #4c97ff
set [clone ID v] to (length of [clone X v] :: #d78c76) :: #f19865
create clone of [myself v] :: #e7bd74
remove this: ({set [clone ID v] to (saved clone ID)} :: ring #321451) :: #FF661A
add this: ({
set [clone ID v] to (parent ID)
set [parent ID v] to (saved parent ID)
} :: ring #f4f752) :: #4c97ff

clones and other workarounds

You can use other workarounds to make working with the clone information easier. For example, this script has a clone rotate around its parent:

(todo)

Give a newly created clone a command

You can't directly use blocks in the same script to tell a new clone exactly what to do. Instead, you can use the name of the costume, or a “for this sprite only” variable, to describe the clone:

// Using costume name

set [saved costume name v] to (costume [name v] :: looks)
switch costume to [asteroid v] // or...
switch costume to [alien v] // or...
switch costume to [shooting star v]
create clone of [myself v]
switch costume to (saved costume name)

// Using a variable

set [saved clone tag v] to (clone tag)
set [clone tag v] to [performance core] // or...
set [clone tag v] to [efficiency core] // or...
set [clone tag v] to [audio controller]
create clone of [myself v]
set [clone tag v] to (saved clone tag)

Then, in a “when I start as a clone” block, check if the costume name or variable matches a specific value, and run the right behavior:

// Using costume name

when I start as a clone
if <(costume [name v] :: looks) = [alien]> then
go to [random position v]
forever
point towards [player ship v]
move (10) steps
end
end

when I start as a clone
if <(costume [name v] :: looks) = [asteroid]> then
go to [random position v]
point in direction (pick random (-180) to (180))
forever
move (2) steps
if <touching [player bullet v]> then
explode :: grey
end
end
end

// Using a variable

when I start as a clone
if <(clone tag) = [performance core]> then
do some really high-speed computations :: grey
end

when I start as a clone
if <(clone tag) = [efficiency core]> then
do lower priority computations :: grey
end

broadcast to specific clone

(todo)

Last edited by _nix (April 7, 2023 19:37:46)

medians
Scratcher
1000+ posts

Scratch Workaround Guide VII

Maybe for broadcast to specific clone, have this?
when I receive [message v]
if <(cloneid) = [1]> then
...
end
Also, switch to costume is the 1.x name for the switch costume to block.

Last edited by medians (March 31, 2023 22:23:43)

vsmeekaryo
Scratcher
66 posts

Scratch Workaround Guide VII

switch to previous costume =

define previous costume
set [previous costume v] to ((costume #)- [1])
switch costume to (previous costume)
medians
Scratcher
1000+ posts

Scratch Workaround Guide VII

vsmeekaryo wrote:

switch to previous costume =

define previous costume
set [previous costume v] to ((costume #)- [1])
switch costume to (previous costume)
This already is in the guide.
5_g
Scratcher
1000+ posts

Scratch Workaround Guide VII

medians wrote:

vsmeekaryo wrote:

switch to previous costume =

define previous costume
set [previous costume v] to ((costume #)- [1])
switch costume to (previous costume)
This already is in the guide.
i have noticed that using this block:
forever
next costume
end
is significantly faster than:
forever
switch costume to ((costume #) + (1))
end
is there any way to “load” a costume for fast access?
INSERT-USER_NAME
Scratcher
1000+ posts

Scratch Workaround Guide VII

I don't know if this is the right place to put this, but I made a timer variable that can be incremented or decremented, and maybe even paused once I figure out how to do that.

This is the script:
when green flag clicked
set [timer var v] to (0)
reset timer
forever {
set [timer var v] to ((timer var) + (timer))
reset timer
}@loopArrow :: control cap

I tested it a bit and it's even accurate to the original timer variable.
INSERT-USER_NAME
Scratcher
1000+ posts

Scratch Workaround Guide VII

5_g wrote:

i have noticed that using this block:
forever
next costume
end
is significantly faster than:
forever
switch costume to ((costume #) + (1))
end
is there any way to “load” a costume for fast access?
I believe if you quickly switch through all the costumes the sprite has, it should effectively “load” all the costumes.
I think there's a script for this as well.

define load
repeat (costumes the sprite has) {
switch costume to ((costume [number v] :: looks) + (1))
}@loopArrow :: control
medians
Scratcher
1000+ posts

Scratch Workaround Guide VII

INSERT-USER_NAME wrote:

define load
repeat (costumes the sprite has) {
switch costume to ((costume [number v] :: looks) + (1))
}@loopArrow :: control
Hold on, did they add that dropdown in 3.0?

INSERT-USER_NAME wrote:

This is the script:
when green flag clicked
set [timer var v] to (0)
reset timer
forever {
set [timer var v] to ((timer var) + (timer))
reset timer
}@loopArrow :: control cap

I tested it a bit and it's even accurate to the original timer variable.
I’ve done that before to keep the timer in the when stop sign workaround like this:
when gf clicked
set [timer v] to [0]
broadcast [timer code v] //that same code
Also, why not just change timer var by timer?

Last edited by medians (April 4, 2023 01:28:07)

INSERT-USER_NAME
Scratcher
1000+ posts

Scratch Workaround Guide VII

medians wrote:

INSERT-USER_NAME wrote:

define load
repeat (costumes the sprite has) {
switch costume to ((costume [number v] :: looks) + (1))
}@loopArrow :: control
Hold on, did they add that dropdown in 3.0?
Yes

medians wrote:

INSERT-USER_NAME wrote:

This is the script:
when green flag clicked
set [timer var v] to (0)
reset timer
forever {
set [timer var v] to ((timer var) + (timer))
reset timer
}@loopArrow :: control cap

I tested it a bit and it's even accurate to the original timer variable.
why not just change timer var by timer?
Those two extra blocks show off my true coding skills /kindajoking

Last edited by INSERT-USER_NAME (April 4, 2023 01:33:20)

_nix
Scratcher
1000+ posts

Scratch Workaround Guide VII

A quick and incomplete 2.0-alike color palette hand-picked with chroma.js, for “transparent” blocks:

({
turn cw (25) degrees
point towards [Sprite2 v]
} #4a6cd4 [#4a6cd4] :: ring #c7c7c7) ({
turn cw (25) degrees :: #8495dd
point towards [Sprite2 v] :: #8495dd
} #8495dd [#8495dd] :: ring #c7c7c7) :: stack #eaeaea
({
switch costume to [Bat1 v]
paint (costume [name v] :: looks) :: #c0c0c0
} #8a55d7 [#8a55d7] :: ring #c7c7c7) ({
switch costume to [Bat1 v] :: #a17edd
paint (costume [name v] :: #a17edd) :: #c0c0c0
} #a17edd [#a17edd] :: ring #c7c7c7) :: stack #eaeaea
({
wait (1) secs
repeat (3)
end
} #e1a91a [#e1a91a] :: ring #c7c7c7) ({
wait (1) secs :: #e7bd74
repeat (3) :: motion #e7bd74
end
} #e7bd74 [#e7bd74] :: ring #c7c7c7) :: stack #eaeaea
({
when green flag clicked
broadcast [message1 v]
} #c88330 [#c88330] :: ring #c7c7c7) ({
when green flag clicked :: #d4a47a
broadcast [message1 v] :: #d4a47a
} #d4a47a [#d4a47a] :: ring #c7c7c7) :: stack #eaeaea
({
set [variable v] to [foobar]
move (speed) steps :: #c0c0c0
} #ee7d16 [#ee7d16] :: ring #c7c7c7) ({
set [variable v] to [foobar] :: #f19865
move (speed :: #f19865) steps :: #c0c0c0
} #f19865 [#f19865] :: ring #c7c7c7) :: stack #eaeaea
({
delete all of [my clones v] :: list
wave to (item (1 v) of [my clones v] :: list) :: #c0c0c0
} #cc5b22 [#cc5b22] :: ring #c7c7c7) ({
delete all of [my clones v] :: #d78c76
wave to (item (1 v) of [my clones v] :: #d78c76) :: #c0c0c0
} #d78c76 [#d78c76] :: ring #c7c7c7) :: stack #eaeaea

Last edited by _nix (April 7, 2023 19:24:10)

_nix
Scratcher
1000+ posts

Scratch Workaround Guide VII

OK, I updated the early-draft clones documentation with a new kind of syntax. Something that's kind of inconvenient to convey in a forum post is adding, removing, or changing blocks in code you already told someone to write. Videos get the advantage of just showing adding, removing or changing blocks, but forum posts are basically static! So I tried using some scratchblocks tricks. All the blocks in the WIP post should be updated, but here's one example:

when green flag clicked :: #d4a47a
add this: ({delete all of [my clones v] :: list} :: ring #f4f752) :: #4c97ff
delete all of [clone X v] :: #d78c76
delete all of [clone Y v] :: #d78c76
... :: #c0c0c0

define create and track clone of myself
... :: #c0c0c0
set [saved clone ID v] to (clone ID :: #f19865) :: #f19865
set [clone ID v] to (length of [clone X v] :: #d78c76) :: #f19865
create clone of [myself v] :: #e7bd74
add this: ({add (clone ID) to [my clones v]} :: ring #f4f752) :: #4c97ff // Keep track of the new clone ID before restoring it.
set [clone ID v] to (saved clone ID :: #f19865) :: #f19865

when I start as a clone :: #e7bd74
add this: ({delete all of [my clones v] :: list} :: ring #f4f752) :: #4c97ff // The clone gets its own list of clones!
... :: #c0c0c0

Let me know what you folk think, especially if anything about this type of writing is tricky to understand or unintuitive! I've never done it before but I also haven't had to talk much about changing existing code. Hopefully this works pretty well, and I'd be glad to experiment more if it could be better or if anyone has other ideas of how to give examples of adding new blocks to, or removing blocks from, existing code.
medians
Scratcher
1000+ posts

Scratch Workaround Guide VII

Uhm, why is it not:
delete (all v) of [list v]
Also what’s the point of the new colors (just wondering)

Powered by DjangoBB