CREATING A SPRITE ARRAY
Posts
Pages:
1
Is it possible to create an array of sprite objects in Ruby?
I'm looking to do something like this:
The important part is being able to refer to the sprite's object with a variable, like:
This is to avoid typing something like this out:
I couldn't find help for this in any Ruby documentation, so I don't know if I'm even approaching the solution to this correctly.
-------------------------------
Edit: Potentially solved. This seemed to work: Spoke too soon; seems like there's a problem with the name being a string.
What the above code does, is creates an array of 20 objects, called
"$my_sprite1"
"$my_sprite2"
"$my_sprite3" etc... up to "$my_sprite21". This looked good, and also threw no errors when each was supposedly converted into a Sprite object with "Sprite.new", but on attempting to refer to them, they only seem to be strings that look like variables, not actual referrable objects that variables are supposed to be.
I'm looking to do something like this:
$thespritemap = Array.new
$thespritemap.each {|x|, $my_sprite|x| = Sprite.new}
The important part is being able to refer to the sprite's object with a variable, like:
$thespritemap[2] # $my_sprite2
$thespritemap[2].bitmap = RPG::Cache.pictures('my_sprite_picture')
This is to avoid typing something like this out:
$my_sprite1 = Sprite.new
$my_sprite2 = Sprite.new
...
$my_sprite200 = Sprite.new
I couldn't find help for this in any Ruby documentation, so I don't know if I'm even approaching the solution to this correctly.
-------------------------------
$thespritemap = Array.new
num = 1
while num <= 20 do
name = '$my_sprite', num
$thespritemap << name
num += 1
end
$thespritemap.each {|x| x = Sprite.new}
What the above code does, is creates an array of 20 objects, called
"$my_sprite1"
"$my_sprite2"
"$my_sprite3" etc... up to "$my_sprite21". This looked good, and also threw no errors when each was supposedly converted into a Sprite object with "Sprite.new", but on attempting to refer to them, they only seem to be strings that look like variables, not actual referrable objects that variables are supposed to be.
Yes this totally possible. However, you're using the each loop incorrectly (over complicating it). There is no need to do this:
The correct way of using this form of loop is to just do this:
Of course, this is assuming that the variable $thespritemap already had some values in it, because you're creating a sprite for each already existing value. However, if you don't have any, what you can do is add this on top of that piece of code, like so:
This would create 15 (+1) indexes in the array, then create a sprite for each empty index.
You can then refer to each sprite individually by using:
So, you can use it for something like this:
Also, I wouldn't recommend using a $ symbol as that denotes a global variable, which can be accessed from anywhere in the code (waste of memory).
$thespritemap.each {|x|, $my_sprite|x| = Sprite.new}
The correct way of using this form of loop is to just do this:
$thespritemap.each {|x| x = Sprite.new}
Of course, this is assuming that the variable $thespritemap already had some values in it, because you're creating a sprite for each already existing value. However, if you don't have any, what you can do is add this on top of that piece of code, like so:
$thespritemap.fill(nil, 0 15) $thespritemap.each {|x| x = Sprite.new}
You can then refer to each sprite individually by using:
$thespritemap[index]
So, you can use it for something like this:
$thespritemap[3].bitmap = Bitmap.new(64,64)
Also, I wouldn't recommend using a $ symbol as that denotes a global variable, which can be accessed from anywhere in the code (waste of memory).
Thanks! Unfortunately, I forgot to specify the RPG Maker I was working in--XP--and it doesn't seem to work with the RGSS built into this one. When the code runs through, it seems as if that step has never registered, simply leaving an array still filled with nil values. (When $thespritemap{number} is then called, it returns a nilClass error.)
$thespritemap.each {|x| x = Sprite.new}Oh, whoops yeah that's my fault. Duh, it's because it doesn't overwrite the previous information in the array, so it's creating sprites which are only referenced by a local variable. Anyway it's even easier, you simply need to do this:
The end result is that the variable: @thespritemap, holds 16 new Sprites.
@thespritemap = Array.new @thespritemap.fill(Sprite.new, 0, 15)
Your most important problem is that you're creating an array with no elements and then trying to iterate over each element. Since there are no elements, Ruby won't do anything.
Additionally, this is wrong:
The problem here is that 'x' isn't part of the array. It's just a name that Ruby lets you use to refer to something.
You shouldn't actually be calling each on your array at all. Probably the best way to do this is to use the array comprehension form of Array.new, which you can find discussed here:
http://www.ruby-doc.org/core-1.8.7/Array.html
Essentially, you want to write something like:
Replacing 10 with however many sprites you actually want.
As for the '$' sign, yes, that creates a global variable. They aren't a "waste of memory" as long as you use them, but it does look to me like what you're doing could potentially end up leading to debugging hell.
What are you actually trying to achieve with this?
EDIT:
This:
is also wrong. The problem here is that this only creates one sprite and then sets each element of the array to that one sprite. The correct version would be:
As for '@thespritemap', that would create an instance variable on whatever the current object is when this code actually gets called. I can't tell you whether or not that's actually what you want, because I don't know the context in which this code appears.
Additionally, this is wrong:
$sprite_array.each {|x| x = Sprite.new}
The problem here is that 'x' isn't part of the array. It's just a name that Ruby lets you use to refer to something.
You shouldn't actually be calling each on your array at all. Probably the best way to do this is to use the array comprehension form of Array.new, which you can find discussed here:
http://www.ruby-doc.org/core-1.8.7/Array.html
Essentially, you want to write something like:
$sprite_array = Array.new(10) {|i| Sprite.new}
Replacing 10 with however many sprites you actually want.
As for the '$' sign, yes, that creates a global variable. They aren't a "waste of memory" as long as you use them, but it does look to me like what you're doing could potentially end up leading to debugging hell.
What are you actually trying to achieve with this?
EDIT:
This:
@thespritemap = Array.new @thespritemap.fill(Sprite.new, 0, 15)
is also wrong. The problem here is that this only creates one sprite and then sets each element of the array to that one sprite. The correct version would be:
@thespritemap = Array.new @thespritemap.fill(0, 15) {|i| Sprite.new}
As for '@thespritemap', that would create an instance variable on whatever the current object is when this code actually gets called. I can't tell you whether or not that's actually what you want, because I don't know the context in which this code appears.
author=pete_mw
Your most important problem is that you're creating an array with no elements and then trying to iterate over each element. Since there are no elements, Ruby won't do anything.
Additionally, this is wrong:
$sprite_array.each {|x| x = Sprite.new}
The problem here is that 'x' isn't part of the array. It's just a name that Ruby lets you use to refer to something.
You shouldn't actually be calling each on your array at all. Probably the best way to do this is to use the array comprehension form of Array.new, which you can find discussed here:
http://www.ruby-doc.org/core-1.8.7/Array.html
Essentially, you want to write something like:
$sprite_array = Array.new(10) {|i| Sprite.new}
Replacing 10 with how many sprites you actually want.
As for the '$' sign, yes, that creates a global variable. They aren't a "waste of memory" as long as you use them, but it does look to me like what you're doing could end up landing you in a world of hurt.
What are you actually trying to achieve with this?
You must have been writing this for a long time, because this was solved more than an hour ago. Remember to refresh!
author=Zachary_Braun
That did the trick! I'll have to remember that .fill method.
Thank you for your help!
Yeah, no problem, glad I could help. Just remember to look through this website here, unless you've already been there. It can be quite handy when looking for methods to use for your code. Of course that website has more than just information on Arrays, it has pretty much everything, just browse through!
Good luck!
Hi Pete,
At this point, this is for a text engine; each sprite is a letter that isn't a font, but a picture. This means that I'd be able to manipulate each letter as its own sprite, maybe get some special effects in there as well that can't be done with a font.
You bring up something I'd like to discuss regarding global variables. When I've attempted to create sprites in the past using the instance-level variable, as soon as the instance is over, the sprites are garbage-collected. I'm still learning, so I'm not sure when instances exactly end. I'm coming from RPG Maker 2003, which required a lot jumping from event to event to common event with "Call Event"s to get this level of functionality.
At this point, this is for a text engine; each sprite is a letter that isn't a font, but a picture. This means that I'd be able to manipulate each letter as its own sprite, maybe get some special effects in there as well that can't be done with a font.
You bring up something I'd like to discuss regarding global variables. When I've attempted to create sprites in the past using the instance-level variable, as soon as the instance is over, the sprites are garbage-collected. I'm still learning, so I'm not sure when instances exactly end. I'm coming from RPG Maker 2003, which required a lot jumping from event to event to common event with "Call Event"s to get this level of functionality.
author=Zachary_Braun
Hi Pete,
At this point, this is for a text engine; each sprite is a letter that isn't a font, but a picture. This means that I'd be able to manipulate each letter as its own sprite, maybe get some special effects in there as well that can't be done with a font.
You bring up something I'd like to discuss regarding global variables. When I've attempted to create sprites in the past using the instance-level variable, as soon as the instance is over, the sprites are garbage-collected. I'm still learning, so I'm not sure when instances exactly end. I'm coming from RPG Maker 2003, which required a lot jumping from event to event to common event with "Call Event"s to get this level of functionality.
You more or less answered your own question. An instance variable is "removed" when the instance itself ends. So, really the question would be what instance are you referring to?
For Example: If you wanted to make the sprites available during battle, you would create them as instance variables for the "Scene_Battle" class. However, once the battle ended, these variables would be disposed.
Does that help?
author=MakoInfused
You must have been writing this for a long time, because this was solved more than an hour ago. Remember to refresh!
Yeah, I'm used to previewing showing me any new posts as well.
However, your solution has problem, which I noted in my edit.
author=Zachary_Braun
You bring up something I'd like to discuss regarding global variables. When I've attempted to create sprites in the past using the instance-level variable, as soon as the instance is over, the sprites are garbage-collected. I'm still learning, so I'm not sure when instances exactly end. I'm coming from RPG Maker 2003, which required a lot jumping from event to event to common event with "Call Event"s to get this level of functionality.
Right. I would recommend finding a tutorial on Ruby itself, and running through it. You might also want to find a book about the language. I'll see what I can do about a crash course on the topic tomorrow: for now, it's midnight and I need to sleep...
author=pete_mw
Yeah, I'm used to previewing showing me any new posts as well.
However, your solution has problem, which I noted in my edit.
Yep, you're right-- strange. I assumed it would execute the code upon "filling".
author=pete_mw
I'll see what I can do about a crash course on the topic tomorrow: for now, it's midnight and I need to sleep...
Right, here's that promised crash course in variables, scoping, and garbage collection.
Objects and Variables:
In Ruby, each object you create is stored in its own dedicated slot somewhere on the 'heap'. There is never more than one of any given object, although two objects can end up looking almost identical.
Variables don't actually store objects. Instead, each variable points to an object -- that is, it allows you to communicate with the object (Variables in dynamic languages have also been described as being like a label you can tie onto an object). Array elements, hash keys, and hash values all work the same way variables do. This is why this code ends up doing seemingly weird things:
@sprite_array = Array.new @sprite_array.fill(Sprite.new, 0, 15)
This appears to be trying to store sixteen sprites in an array. However, because you've only created one sprite, and because Ruby doesn't really store sprites in an array, what actually happens is that you end up with an array with sixteen elements, all of which actually point to the same sprite.
Instead, you should use this:
@sprite_array = Array.new @sprite_array.fill(0, 15) {|i| Sprite.new}
This form of Array#fill calls the attached block for each element it modifies, and sets that element to whatever the block returns. That means you're calling Sprite.new sixteen times, so you end up with sixteen sprites.
The reason the first, 'broken' form of Array#fill and friends exists at all, in case you're wondering, is because for 'immutable' objects -- ones that never change -- it doesn't actually make any difference to your code whether you're creating actual copies or simply creating new pointers.
Garbage Collection:
Once created, an object lasts until Ruby decides that there's no chance that you'll ever talk to it. It shouldn't be possible for an object to be garbage-collected while you actually need it. Depending on what kind of variable points to an object, it might be visible under different circumstances.
Constants:
Constants belong to modules, but they are normally globally-accessible, which means they will not be garbage collected. Once you have assigned to a constant, you may not do so again, but constants do nothing to stop you from modifying the objects that they point to.
Local Variables:
Local variables are visible from within the method (or begin...end block) that defined them, and from within any closures (that is, {} or do...end blocks) that method creates. Each time you call a method, a new set of local variables is created.
Instance Variables:
Instance variables belong to an object. Once created, they last for as long as their owner does, and they are visible as long as their owner is the current object. As long as an object is reachable, so are any objects pointed to by its instance variables.
An instance variable is created by prefixing its name with an @ sign.
Global Variables:
Global variables belong to the program as a whole. A global variable is visible from any piece of code within your program, so as long as an object is pointed to by a global variable, it is always reachable.
Class Variables:
A class variable belongs to a class, and is visible whenever that class or one of its instances is the current object.
Hope this helps.
Thanks a lot for the correction and the crash course. I'm learning more and more every day!
On that note, here's my last question, something more particular to how RPG Maker works with Ruby: Inside the RPG maker engine, does the command interpreter for the command lists inside a single event page count as a single instance? For example, when calling a common event, is everything inside that common event a single instance? Or does it extend to the event which in turn called the common event?
On that note, here's my last question, something more particular to how RPG Maker works with Ruby: Inside the RPG maker engine, does the command interpreter for the command lists inside a single event page count as a single instance? For example, when calling a common event, is everything inside that common event a single instance? Or does it extend to the event which in turn called the common event?
It depends on where the common event is being called. Basically the map class and battle system class have their own instances of Interpreter. If you're on the map, event commands will be processed by $game_map's Interpreter. If you're in battle, event commands will be processed by the battle system's Interpreter.
As a corollary to this, if you create your own scenes and want to use Interpreter commands, you'll have to create an instance of Interpreter in your custom scene as well.
As a corollary to this, if you create your own scenes and want to use Interpreter commands, you'll have to create an instance of Interpreter in your custom scene as well.
Pages:
1














