Better ways to manage large numbers of sprites than gigantic lookup tables?


#1

The attached .apk and .aia demonstrate a 4 item by 4 item grid of non-moving sprites, that are randomly located on the screen when it is initialized. The “dirt” objects blink on and off when touched (using the fixed image size and blank image label trick).

Since, apparently, there’s no way to iterate or otherwise programmatically manipulate sprites (objects in general?), I created an if/then table (since I don’t see the equivalent of a “switch” statement anywhere) that matched specific strings to specific sprites along with enabling specified actions on them (setting X and Y coordinates), created a list that contained those strings and shuffled it, then assigned each item in that list a unique X,Y coordinate via a for each item loop.

Note: this is a prototype, demonstration case. The final game is going to have much more logic and anywhere from 160 to 300 sprites (of the type referenced), so unless there’s a better way, this is obviously going to involve hacking the XML and JSON to create the blocks and objects (already done). Right now, there’s two sets of blocks for each object, one in the if/then table, and one for the action to take when a sprite is touched, so we’re looking at, quite possibly, nearly 1000 blocks on the Screen where the action is taking place.

Question 1: Am I correct in my understanding that there’s no way to directly convert a variable name into an object name that can be manipulated? I.e., instead of having an if / then table that calls a procedure after mapping the content of a variable to a specific object, being able to pass the name of an object (sprite) to a procedure directly, with maybe some conversion logic that says, “turn this string into an object name”?

Question 2: is there any more rational way of dealing with 160 to 300 sprites than creating a block of duplicate logic for each and every one? It seems like I should be able to dynamically derive the name of a sprite that happens to be occupying a particular X,Y coordinate, and then pass that to a single set of code blocks that define what should happen.

I can use the Canvas.Touched block to derive the X and Y coordinates of a touch, derive the sprite name from a list (lookup table) containing the name and location of every sprite (since they’re static and not moving), and then use the my already existing if/then look up by sprite name table to trigger specific actions (like setting the visible/invisible property of a particular sprite, or the picture property)… but this seems incredibly hackish and perverse, when the system already knows exactly what sprite I just touched, and should then be able to invoke the standard blocks associated with it. Not to mention that I suspect this is going to be horribly inefficient along a number of vectors (and make the AB block editor interface spaz out completely when the lookup tables are touched).

Am I missing something?

SpriteScramble.aia (17.5 KB)
SpriteScramble.apk (2.1 MB)


#2

You can create a list that includes your sprites, then use Advanced Any to iterate through list


#3

Right, I see that in the checkbox advanced features tutorial by @Taifun, that lets me get rid of the lookup table, but then I have to initialize 160-300 items when the screen opens, and unless I’m mistaken, I can’t programmatically generate that list or build it from a file/csv, each object has to be individually added to the list (and the list has to be manually mutated to contain the correct number of objects). I see the same requirement in the MIT Tutorial Using Procedures and Any component blocks and again in the Pvest tutorial Storing and accessing user interface components as variables.

There’s still no way to directly convert a string into a object name and then address the object. Which, I guess makes sense, if you’re going to be manually creating each and every object in the designer, it is reasonable to then manually create each associated block as well.

It would save, a step, at least, if I could, instead of dragging and dropping each individual element into a list, instead say, “add X number of items” to a list component, surely that’s not a fundamental architectural change, per see, but rather a relatively minor UI modification to the mutator interface.

Err… it appears that using ListUtils to “Shuffle” a list of components converts that list into a list of strings? I’m getting a runtime error when I attempt to manipulate the list: “Property setter was expecting a com.google.appinventor.components.runtime.ImageSprite component but got a String instead.”

That suggests that the opposite should also be possible: converting a list of strings into a list of component names.


Shuffling for DynamicComponent
#4

Note: being able to define a list of sprite objects eliminates a huge chunk of the previous code, which is very nice, definitely a win in that respect. Assuming there’s a way to fix the runtime error with ListUtils.


#5

@Hossein Did you catch that the Shuffle block from the ListUtils extension converts sprite types to strings and thus can’t be used to manipulate a list of sprites? I can work around this by reading locations into an array, then shuffling that, and iterating through the sprites, but it is cleaner to just iterate through a shuffled list of sprites, assigning them to locations as they are encountered. Shouldn’t a block be expected to preserve the type passed to it, unless it explicitly converts it?


#6

@Thomas_Leavitt I’ll check into it


#7

Revisiting my questions:

Being able to store a list of sprites in a list is very useful, but I’m still limited in my ability to manipulate them, as it appears that there’s no way to directly extract the name of a sprite or match on it. There are a ton of useful things that could be done if this simple functionality were available: “show all sprites with ‘soil’ in name”, “iterate through sprite00 to sprite07”, etc. etc.

Question 1: Am I correct in my understanding that there’s no way to directly convert a variable name into an object name that can be manipulated? If not, I’d like to request this as a feature, and, ideally, abstract the functionality so that it is available for all objects.

Question 2: is there any more rational way of dealing with 160 to 300 sprites than creating a block of duplicate logic for each and every one? It seems like I should be able to dynamically derive the name of a sprite that happens to be occupying a particular X,Y coordinate, and then pass that to a single set of code blocks that define what should happen.


#8

I used the ShuffleList procedure from Imagnity’s tutorial Shuffle Lists & Unique Random Numbers as a work around in the meantime.


#9

@Thomas_Leavitt sorry but I’m not clear on why you add all that shuffle logic and not using ListUtils shuffle. I posted an example that shuffled list of sprites. Sorry if I missed your point


#10

This is what I get when I attempt to Shuffle a list of sprites.

The two lists are initialized.

58 AM

Then listSprites is populated in the ScreenBoard.Initialize event handler, after which, the following blocks are used. They produce the error above.


#11

For me it worked. See link below. When I get access to computer, I’ll post .aia


#12

Hmm… o.k., interesting. It appears that it’s somewhere else in my code, that somehow is not being triggered when I use the workaround logic, which is odd, since the code is being fed the same list, just in one case, being manipulated through the ListUtils, and the other case, being manipulated through the workaround logic.

So, here’s an example function that attempts to iterate through the list returned by ListUtils.Shuffle, and generates that error:

09 AM

When I simply replace the ListUtils.Shuffle with the workaround logic, I don’t get that error. It seems that somehow, your code is converting a list of sprites, to a list of strings.


#13

I’ll put together a sample .aia and skate by tomorrow.

If anyone else has similar code, please share


Screen Interaction
#14

FYI, I tested it by assigning the output of the get function to the text property of a Label, and both lists seem to produce output.


#15

So, I put the screen initialization logic in a button, and used the Do It function on the foreach loop intended to iterate through the list of sprites, and this is what I got:


#16

@Thomas_Leavitt You are correct and shuffling for List of Components isn’t working. We’ll check into it.


#17

@Thomas_Leavitt I was thinking and came up with below approach that works perfectly using 1 Shuffle block. Won’t this work for you??

You could even use “length of list” instead of hard-coding:
image