I want to loop the background image in a Ruby gosu side scrolling game.I have problem with the counters @k
and @p
which are used to translate the background image and the duplicated background image.I can't think of a good way to plus them.Here's the code to make it more clear.
require 'gosu'
class GameWindow < Gosu::Window
attr_accessor :x, :y
SHIFT = 700
def initialize
super 640,440
@background = Gosu::Image.new("./images/bg.png")
@player = Gosu::Image.new("./images/000.png")
@x1, @y1 = 0, 0
@player_x, @player_y = 50, 50
@k = 0 #counter
@p = 1 #counter
end
def update
@x1 -= 3
@player_y += 1 if @player_y <= 375
@player_y -= 3 if button_down?(Gosu::KbSpace) and @player_y >= 0
@coordinates = Gosu::Image.from_text(
self, "#{@x1},#{@k}", Gosu.default_font_name, 30)
#here should be the code for @k and @p
end
def draw
@background.draw(@x1 + @k*SHIFT, @y1, 0)
@background.draw(@x1 + @p*SHIFT, @y1, 0)
@player.draw(@player_x, @player_y, 0)
@coordinates.draw(0, 0, 1)
end
def button_down(id)
$window.close if id == Gosu::KbEscape
end
end
window = GameWindow.new
window.show
So how do I plus the counters @k
and @p
.Tried this
if @x1 > -(SHIFT+5)*@p and @x1 < -SHIFT*@p #705 and 700
@k += 2
end
if @k > 0 and @x1 > -SHIFT*@k - 5 and @x1 < -SHIFT*@k - 3 #1405 and 1403
@p += 2
end
but it works only in the beginning(2-3 image shifts). Also tried this
if @x1 == -SHIFT*@p
@k += 2
end
and it did not work.
I'm assuming that @x1
and @y1
are the offset of the left-most background's origin relative to the screen. You also have @player_x
and @player_y
, which denote the player's position on the screen. Your player is kept horizontally in the center of the screen, moving vertically when jumping or falling, and your background only scrolls horizontally. Also, your window size is 640x440, and your background image is 700px wide and at least 440px tall.
Your update
step handles things like jumping (but only to the top of the screen) and simple, constant-velocity gravity, both by modifying the player's screen coordinates. It also provides a constant horizontal scroll by subtracting 3 units per frame from @x1
, the horizontal camera coordinate in world-space.
Your draw
step then takes the background image and draws two of them, offsetting them by the camera offset @x1
plus the shift for which image is which. This shift, however, isn't important, because we can calculate it fairly simply, and we're left without having to manipulate the additional state of remembering which one is which.
Instead of remembering the counter values @k
and @p
, we're going to just modulo by the image width to eliminate the excess in @x1
and get it where we need it to be. @k
and @p
are useless, so delete those. SHIFT
can be deleted as well.
Instead, we need to do the following:
Our goal looks something like this:
Our new code:
require 'gosu'
class GameWindow < Gosu::Window
attr_accessor :x, :y # side note - are these used at all?
def initialize
super 640,440
@background = Gosu::Image.new("./images/bg.png")
@player = Gosu::Image.new("./images/000.png")
@x1, @y1 = 0, 0
@player_x, @player_y = 50, 50
end
def update
@x1 -= 3
@player_y += 1 if @player_y <= 375
@player_y -= 3 if button_down?(Gosu::KbSpace) and @player_y >= 0
@coordinates = Gosu::Image.from_text(
self, "#{@x1}", Gosu.default_font_name, 30)
end
def draw
# the important bits!
@local_x = @x1 % -@background.width
@background.draw(@local_x, @y1, 0)
@background.draw(@local_x + @background.width, @y1, 0) if @local_x < (@background.width - self.width)
@player.draw(@player_x, @player_y, 0)
@coordinates.draw(0, 0, 1)
end
def button_down(id) # Side note: Does this work correctly?
$window.close if id == Gosu::KbEscape
end
end
window = GameWindow.new
window.show
What this does is, it takes @x1
and modulos it with the (negative) width of the image. This means, it gives the remainder of an integer division of the two numbers. Modulo is very useful when trying to ensure that an integer value "wraps around" after exceeding a limit in either direction; it effectively maps it to between 0 (inclusive) and the given number (exclusive). The results of this are illustrated in the graphic above.
Keep in mind this solution only works as-is for your circumstances; vertical scrolling will require more code, and this will break pretty quickly if your window becomes wider than your background image.