[noob] Problem with arrays

S

Sylvain Petit

Hello,

I have a few issue using arrays.

I'm working with rubySDL to make a vertical shooting game. I have a
ship, which had a collection of "fired_missile".
The level have a collection of critters on screen.

My main loop is :

def main
self.init_lvl
critest = Critters.new(@screen, SCREEN_W,SCREEN_H/2)
@crit<<critest
while(@finished == false)
background = @screen.format.map_rgb(0, 0, 0)
@screen.fill_rect(0,0,@screen.w,@screen.h,background)
self.event_poll
@ship.move
@ship.draw
cur_crit = @crit
cur_crit.each { |c|
c.move
c.draw
self.check_firing(c)
}
@screen.update_rect(0,0,@screen.w,@screen.h)
end
end

If I understand my code well, for each critters in @crit collection (or
cur_crit to be more accurate), I move the crit, then draw it, and to
finish I call "check_firing" with the critters in parameter.

Here's the check_firing code :

def check_firing(c)
critemp = []
if(@ship.firelist.length!=0)
@ship.firelist.each { |f|
if(f.collide_with?(c))
else
critemp<<c
end
@crit = critemp
}
end
end

The amusing part is that all work well if I fire only one missile. When
I fire more, it becomes unclear : the critters won't disappear, and
(surprisingly) it goes faster.

I used the cur_crit temporary array in the main function because
modifying the @crit array while looping on it was kind of hazardous.

If someone have an idea, it will be greatly appreciated ;)
Thanks.
 
S

Sylvain Petit

Ok, my mistake, I was lost in loops :p

So, to explain that simply, I passed c as an argument so it became
persistant outside the @crit.
 
M

Marnen Laibow-Koser

Sylvain said:
Hello,

I have a few issue using arrays.

I'm working with rubySDL to make a vertical shooting game. I have a
ship, which had a collection of "fired_missile".
The level have a collection of critters on screen.

I saw your later post that this is working, but I thought that since
you're a newcomer, I'd just point a few things about your programming
style that aren't so Rubyish...
My main loop is :

def main
self.init_lvl
critest = Critters.new(@screen, SCREEN_W,SCREEN_H/2)

If each instance of this class represents one critter, then it would
usually best to call the class Critter (in the singular).
@crit<<critest

I think most Rubyists use spaces around operators, for what that's
worth...
while(@finished == false)

You don't need the parentheses or the "== false". You probably just
want "while !@finished".

Caveat: that will also return true if @finished is nil.
background = @screen.format.map_rgb(0, 0, 0)
@screen.fill_rect(0,0,@screen.w,@screen.h,background)
self.event_poll
@ship.move
@ship.draw
cur_crit = @crit
cur_crit.each { |c|

In general, "do...end" is used for multiline blocks. The {} syntax is
usually reserved for blocks on a single line. It is *very* rare to use
{} as you've used it here.
c.move
c.draw
self.check_firing(c)
}
@screen.update_rect(0,0,@screen.w,@screen.h)

That's a long loop! Why not put it in a method of its own? You might
also want to put the cur_crit.each block in a method of its own.
end
end

If I understand my code well, for each critters in @crit collection (or
cur_crit to be more accurate), I move the crit, then draw it, and to
finish I call "check_firing" with the critters in parameter.

Here's the check_firing code :

def check_firing(c)
critemp = []
if(@ship.firelist.length!=0)

Unnecessary. If the length is 0, then the each in the next line will
simply perform its block 0 times.

Now, if firelist could be nil, then you'll need to check for that. "if
@ship.firelist" would be sufficient.
@ship.firelist.each { |f|
if(f.collide_with?(c))
else
critemp<<c
end

Why do you have an empty if clause? You could make this much more
readable by reversing the conditional (and removing some parentheses):

if !f.collide_with?(c)
critemp << c
end
@crit = critemp
}
end
end

Are you sure about your logic here? The only thing that will be written
to @crit is an array containing multiple copies of c. No further
information, just multiple copies of c.

Best,
 
L

Luc Heinrich

You don't need the parentheses or the "=3D=3D false". You probably = just=20
want "while !@finished".

Even better: until @finished
if !f.collide_with?(c)

Same here: unless f.collide_with?(c)

--=20
Luc Heinrich - (e-mail address removed)
 
M

Marnen Laibow-Koser

Luc said:
Even better: until @finished

Thanks! I forgot about until.
Same here: unless f.collide_with?(c)

I don't like unless. I find it less confusing, in most cases, to write
if !. But it certainly is an option.

Best,
 
J

Josh Cheek

Even better: until @finished


Same here: unless f.collide_with?(c)
I would also define getters for boolean variables

def finished?
!!@finished
end

...

until finished?
...
end


I try to restrict direct references to instance variables, and instead use
them through methods, it seems like better encapsulation to me. For example=
,
maybe later I realize I can tell if it is finished by checking something
else rather than storing state in an instance variable, then there is only
the setter and getter methods that need to be looked at, rather than every
place I used the instance variable.

I guess I see the method as an interface to the functionality, and the
instance variable as the implementation.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top