Discuss Scratch

sippingcider
Scratcher
500+ posts

Help with making my project run faster

I have been working on this project for some time. It is a spaceship battle that draws a lot of objects and updates a lot of objects often (mostly laser bullets and stars). Right now everything is drawn with pen and done in one sprite. My computer can run the game pretty well with 5 cruisers, but when I add more it slows down a lot and on most other computers it runs even slower. My general question is how can I make it run faster? Some more specific questions are:

-Does doing everything in one sprite work best or should I try splitting up my code between more sprites?

-Is drawing objects with pen the best or should I use costumes and stamp them? (cloning has been super slow with me so I am guessing I shouldn't use cloning).

-Anything that will help speed this up would be nice to know too.

P.S. I am not sure if this is the best place to post this or if this would go in the AT section.
WolfCat67
Scratcher
1000+ posts

Help with making my project run faster

It seems pretty good on my computer; might just be computer speed?
Also, the amount of lasers the enemies fire seems a bit… Overkill? There seem to be more lasers fired in 10 seconds than there are in the entire Star Wars series.
IronBit_Studios
Scratcher
1000+ posts

Help with making my project run faster

phosphorus.github.io
awesome5I85
Scratcher
29 posts

Help with making my project run faster

IronBit_Studios wrote:

phosphorus.github.io
You can't edit it after then
~
I think it's just your computer; is it old? If you want a smoother gameplay, use the above website only AFTER you have 100% finshed your game as you can't edit it after then. If you want to, you're gonna have to edit it, save it and repeat the process again. Quite a hassle just for testing.
awesome5185
Scratcher
1000+ posts

Help with making my project run faster

awesome5I85 wrote:

IronBit_Studios wrote:

phosphorus.github.io
You can't edit it after then
~
I think it's just your computer; is it old? If you want a smoother gameplay, use the above website only AFTER you have 100% finshed your game as you can't edit it after then. If you want to, you're gonna have to edit it, save it and repeat the process again. Quite a hassle just for testing.
-_- the 120 second rule!? I'll be using this account to answer further questions on this topic.
TheMonsterOfTheDeep
Scratcher
1000+ posts

Help with making my project run faster

awesome5I85 wrote:

IronBit_Studios wrote:

phosphorus.github.io
You can't edit it after then
What do you mean? All phosphorus is is a project player; if you run your project in it it will go faster.

That being said, it's not a solution to making your project faster *in Scratch*.
sippingcider
Scratcher
500+ posts

Help with making my project run faster

It seems pretty good on my computer; might just be computer speed?
Also, the amount of lasers the enemies fire seems a bit… Overkill? There seem to be more lasers fired in 10 seconds than there are in the entire Star Wars series.

Yeah computer speed definitely seems to affect it, ideally I would like for this to be able to run on older computers because a lot of my family and friends use older computers. And lol at the star wars , but I am going for a super chaotic heat of the battle feel in this game so thats why there are so many lasers.


phosphorus.github.io

Woah this is awesome!! Some of the colors are not showing up right, like the ship color and menu highlighting color, but this does run it a lot faster and it actually goes full screen!
TheMonsterOfTheDeep
Scratcher
1000+ posts

Help with making my project run faster

I imagine that a huge factor is delete operations - these get really slow with bigger lists (their time complexity is O(n)).

It may be possible to increase speed by doing fewer deletes. What you would do is instead of deleting a laser, simply set a state that indicated that that spot in the list was empty. Then, when you create a new bullet, find the first empty slot and place it there. The problem, of course, is that finding a new empty slot is also O(n) - so it may not result in any speedup (especially because if I recall correctly replace operations are slow in Scratch for some reason…)

Sadly Scratch does not have some sort of access to linked lists, because that would make it very simple to get a massive speedup. You could potentially try to implement some sort of linked list - but I have no idea how fast it would be, or if it would have any advantage.

Or, of course, I could be wrong entirely and deletes have nothing to do with it - but it's the first thing I would suspect.
TheLogFather
Scratcher
1000+ posts

Help with making my project run faster

TheMonsterOfTheDeep wrote:

…if I recall correctly replace operations are slow in Scratch for some reason…
There was a time, way back a few years ago, when list replace was done in a very bad way in Scratch. However, it's fast now (the fastest list operation except append), so it's way better, if you can, to replace than to delete and add.

But it really depends how often the deletes happen, compared to how much extra work it is to do a load of replacing instead.

One possibility might be to do as TheMonsterOfTheDeep suggests above – having entries flagged as ‘finished’, so they're ignored – and then every so often (couple of times per second?) ‘compress’ the lists, so that all the empty entries get removed – but do it by shifting all the items down into the gaps, and then delete the remaining items, starting from the end (deleting the final item is much quicker than the items nearer the beginning).

Another possibility would be to keep a list of the empty slots, adding to the end of that list when you make an empty slot, and taking off the end when you want to use one. That would mean you never add or delete any of the object items, just replace them (so you'd start off with them filled up to some maximum). As long as the maximum number of used+unused slots isn't too much greater than the typical number of slots it currently uses, then it should be an improvement.


Another speed-up would be to avoid all that atan2 stuff, and just take a point's co-ordinates (offset by ship's co-ords) and rotate by the ship's direction. You should pre-calculate cos(dir) and sin(dir) into variables, so it's not doing those operations for every point. That would mean each rotation is just four multiplications and two adds (two plus one for each of x & y co-ord), instead of all that script in the atan2 plus the sin and cos of the angle for every point.


Hope that helps!

sippingcider
Scratcher
500+ posts

Help with making my project run faster

@TheMonsterOfTheDeep and TheLogFather

Thanks for your suggestions about replacing items in my lists instead of deleting/adding, however it seems to be running slower after this change.
As long as the maximum number of used+unused slots isn't too much greater than the typical number of slots it currently uses, then it should be an improvement.
I guess the typical number of slots it was using was a lot less than the maximum slots it is using now. Still, that idea sounded good and was creative for sure!

@TheLogFather

Another speed-up would be to avoid all that atan2 stuff, and just take a point's co-ordinates (offset by ship's co-ords) and rotate by the ship's direction. You should pre-calculate cos(dir) and sin(dir) into variables, so it's not doing those operations for every point. That would mean each rotation is just four multiplications and two adds (two plus one for each of x & y co-ord), instead of all that script in the atan2 plus the sin and cos of the angle for every point.

Another really cool idea, thanks for this suggestion. Sadly, after making this change I did not notice any difference in speed for the program. It should definitely be reading a lot less code than before, but I guess the math calculations just happen really fast in scratch compared to other blocks.
TheLogFather
Scratcher
1000+ posts

Help with making my project run faster

One thing I've just noticed is that you're using “point in direction”, but you have your sprite set to rotation style “all around” – switch to rotation style “don't rotate”. See why here: https://scratch.mit.edu/projects/121320890/

Also, don't use recursion in your custom blocks. There's no reason not to use a loop.

And take those “set pen color” and “set pen size” blocks out of the loop – everything that gets drawn in the loop is the same size and colour, so they're only needed at the start.

Maybe all of those together will make some difference…



Last edited by TheLogFather (March 27, 2017 19:59:02)

sippingcider
Scratcher
500+ posts

Help with making my project run faster

One thing I've just noticed is that you're using “point in direction”, but you have your sprite set to rotation style “all around” – switch to rotation style “don't rotate”. See why here: https://scratch.mit.edu/projects/121320890/

Thanks, this alone made a difference of 1-2 extra updates per second!

Also, don't use recursion in your custom blocks. There's no reason not to use a loop.

Don't scratch loops take up extra time in-between iterations? I know this can be bypassed with turbo mode but I don't want to tell people they have to run the game in turbo mode.

And take those “set pen color” and “set pen size” blocks out of the loop – everything that gets drawn in the loop is the same size and colour, so they're only needed at the start.

Ok so this also made a difference of about 1-2 extra updates per second. Did not expect that to make such a difference. Thanks!

Last edited by sippingcider (March 27, 2017 20:24:40)

TheLogFather
Scratcher
1000+ posts

Help with making my project run faster

sippingcider wrote:

Don't scratch loops take up extra time in-between iterations? I know this can be bypassed with turbo mode but I don't want to tell people they have to run the game in turbo mode.
Only if there's a refresh between. If you switch off refresh for a custom block then Scratch runs loops inside that custom block script at full speed.

Non-refresh is faster than turbo because turbo still checks at the end of each pass of a loop if it needs to yield to another script that's running concurrently. (Loops still run concurrently in turbo.)

But non-refresh is ‘atomic’. That means *no* other scripts can run until the non-refresh one finishes (or until the half second non-refresh limit is reached). So it doesn't do the check for yield at the end of each pass of the loop.


Another thing I'd do would be to avoid setting the pointToDrawX/Y variables, and instead just pass those expressions straight into the rotation custom blocks. You could probably then delete those two vars.


Another thing I noticed is that you're always calculating sin and cos of the bullet angles. You could store the xvel and yvel instead. That means two lists rather than one, so it's touch-n-go whether it'd be better, but worth a try. It also would mean you didn't need to “point in direction”, and you would go to the old list x,y position, then update them, pen down, then go to new positions. Again, very hard to say it'll be better, but it's possible.


Last edited by TheLogFather (March 27, 2017 20:33:05)

TheLogFather
Scratcher
1000+ posts

Help with making my project run faster

TheLogFather wrote:

Another thing I noticed is that you're always calculating sin and cos of the bullet angles. You could store the xvel and yvel instead…
Actually, probably scrap that one – the xvel/yvel would need to change as the player rotates, so that'd probably end up ruining any speed benefits.

Also, the pointToDrawX/Y vars get used in the rotation block, so you obviously can't delete them. (Dunno what I was thinking. )


One other thing, not to do with speed…

Fill the costume with black – so it becomes a 480x360 black rectangle. That will make everything draw off the edge of the screen correctly (instead of the drawing getting ‘warped’ as it goes off the edge). And hide the sprite. As long as your sprite is set to rotation style “don't rotate” then it won't cause any problems, even though you're changing its direction.

That would also mean that you can push all of the drawing out to cover the whole screen, without needing to restrict it to just the circle (unless maybe you intend to make that into a kind of ‘radar-scanner-like’ circle, and have other control data/info drawn off the right & left sides of it), so you can increase the limits at which ‘clip’ the cruisers (so they ‘glide’ more gracefully off the screen edges).

Last edited by TheLogFather (March 27, 2017 20:49:47)

sippingcider
Scratcher
500+ posts

Help with making my project run faster

One other thing, not to do with speed…

Fill the costume with black – so it becomes a 480x360 black rectangle. That will make everything draw off the edge of the screen correctly (instead of the drawing getting ‘warped’ as it goes off the edge). And hide the sprite. As long as your sprite is set to rotation style “don't rotate” then it won't cause any problems, even though you're changing its direction.

That would also mean that you can push all of the drawing out to cover the whole screen, without needing to restrict it to just the circle (unless maybe you intend to make that into a kind of ‘radar-scanner-like’ circle, and have other control data/info drawn off the right & left sides of it), so you can increase the limits at which ‘clip’ the cruisers (so they ‘glide’ more gracefully off the screen edges).

Thank you so much!!!!!!!!!!!! I have been dreading how much code I would have to do to fix this warping problem, and it turns out all I had to do was 2 steps! Right now I am liking the radar feel of the circle and probably won't change it unless I end up adding a minimap later.

As for the loops/recursion, is there any benefit to replacing the recursion with loops besides making the code more readable? Right now I am feeling kind of lazy and not wanting to replace all of it

Last edited by sippingcider (March 27, 2017 21:02:51)

TheLogFather
Scratcher
1000+ posts

Help with making my project run faster

sippingcider wrote:

As for the loops/recursion, is there any benefit to replacing the recursion with loops besides making the code more readable? Right now I am feeling kind of lazy and not wanting to replace all of it
It's very quick to make the changes.

It goes from:
definedrawsomethingchangecountby1doallthecalculation,checks,anddrawing...ifcount<lengthofsome listthendrawsomething

To this:
definedrawsomethingchangecountby1 only 'cos you set to 0 before calling custom block -could avoid that, and set to 1 here insteadrepeatuntilcount>lengthofsome listdoallthecalculation,checks,anddrawing...changecountby1 note this operator has flipped from < to >

The main thing it will save is an internal search to find the custom block definition at each pass through the loop. (When you call a custom block, Scratch has to go through all the scripts in the sprite, looking for one that's a custom block that matches the one you've called. It's very fast, but it might make a slight difference, since you're really doing it loads of times…)

Actually, it'll also save building a large return stack. For the stars, for example, you have several hundred nested calls. Again, each one is really fast, but if it's building up the memory like that, it might add up to something overall.


Also, the main ones to do it on would be the stars and the enemy bullets. I reckon it takes about a minute to do both of those…
(Player bullets would be next, and I suspect the others would make no noticeable difference.)

Last edited by TheLogFather (March 27, 2017 21:20:17)

sippingcider
Scratcher
500+ posts

Help with making my project run faster

It's very quick to make the changes.
.
.
.
.
The main thing it will save is an internal search to find the custom block definition at each pass through the loop. (When you call a custom block, Scratch has to go through all the scripts in the sprite, looking for one that's a custom block that matches the one you've called. It's very fast, but it might make a slight difference, since you're really doing it loads of times…)

Actually, it'll also save building a large return stack. For the stars, for example, you have several hundred nested calls. Again, each one is really fast, but if it's building up the memory like that, it might add up to something overall.


Also, the main ones to do it on would be the stars and the enemy bullets. I reckon it takes about a minute to do both of those…
(Player bullets would be next, and I suspect the others would make no noticeable difference.)

Ok I did it. Wishing scratch had a search option or replace all option but it wasn't to hard. You should be a scratch coach haha.

Last edited by sippingcider (March 27, 2017 22:33:35)

jji10
Scratcher
1000+ posts

Help with making my project run faster

Doesn't lag at all for me. Maybe you need a computer upgrade or something?
slimekitchen
Scratcher
1 post

Help with making my project run faster

I imported a song from files and so far is taking 30 minuets.
Abigblueworld
Scratcher
500+ posts

Help with making my project run faster

A good trick is too not add alot of sprites, backdrops or sounds. It produces
Less lag on mobile or slow computers.
May have better performance.
Try that!

Powered by DjangoBB