Options

# Map scrolling nightmare...

• #### Index

• Map scrolling nightmare...
• I was trying to implement a map scrolling system thanks to Gosu's translate method that semiautomatically handles tiles and events offsets making it easier for game developers to handle more ordinary stuff than usual while drawing a map. Sadly you end up watching how my player and his not so heroic team makes the map look larger and darker than expected. I'm not really used dealing with scrolling issues so I thought somebody here could tell me what I'm doing wrong here hopefully... For now solving the issue with the horizontal map scroll should suffice. I only commented those lines that somehow affect map scrolling.

This happens when I go left... (Those two lonely tiles denote the actual end of the map on the righthand side.)

And this is the disaster that takes place if I go right...

Code:
```class Player   def update     return if @halt     @last_x = @screen_x     @last_y = @screen_y     return if moved?     if Gosu.button_down?(Gosu::KbDown)       @dir = @other_way ? 8 : 2       return unless pass?       @y += 0.5#actual_speed       @screen_y = @y * 16       update_steps     elsif Gosu.button_down?(Gosu::KbUp)       @dir = @other_way ? 2 : 8       return unless pass?       @y -= 0.5#actual_speed       @screen_y = @y * 16       update_steps     elsif Gosu.button_down?(Gosu::KbLeft)       @dir = @other_way ? 6 : 4       return unless pass?       @x -= 0.5#actual_speed       @screen_x = @x * 16       ### Calculating the horizontal offset, Current direction: Left (4)       @offset_x = [0, -@screen_x].min if @screen_x < Map.width * 16       update_steps     elsif Gosu.button_down?(Gosu::KbRight)       @dir = @other_way ? 4 : 6       return unless pass?       @x += 0.5#actual_speed       @screen_x = @x * 16       ### Calculating the horizontal offset, Current direction: Right (6)       @offset_x = [[-@screen_x + @last_x, -Map.width * 16].max, 0].min if @screen_x > Map.width * 16       update_steps     end     if button_down?(:enter) or button_down?(:return)       Map.events.each do |event|         blocked = block_pass?(event)         next unless blocked         event.react_now if event.react         if event.button?           event.activate           @halt = true           return         end       end     end   end end class SceneMap   def update_scene     @offset_x = @player.offset_x # saving last horizontal offset     @offset_y = [-@player.screen_y + @window_height / 1.08, 0].min     if @map_ticks > 0       @map_ticks -= 1       @map_texts.clear if @map_ticks == 0     end     @player.update # Calling Player's Update Method and setting a new horizontal offset value     Map.events.each {|e| e.update }     @spriteset.update     if press_quit?       Game.cancel_se.play       Game.setup(SceneKUnitsMenu)       return     elsif button_down?(:left_ctrl)       Game.ok_se.play       Game.setup(SceneKUnitsAchieve)     elsif button_down?(:caps_lock)       Game.ok_se.play       Game.setup(SceneKUnitsFoes)     elsif button_down?(:left_shift)       Game.ok_se.play       Game.setup(SceneKBookPages, id: 1)     end   end   def draw     @window.clip_to(0,0,@window_width,@window_height) do # Some sort of Viewport singleton command       @window.translate(@offset_x,@offset_y) do # Scroll loop         @spriteset.draw       end     end     @map_texts.each {|text| text.draw }   end end```

You can find the rest of the code in the KUnits script thread, just check out the main post there.
Guess what? I solved it, not thanks to you, guys -_- (Yeah, I'm a bit disappointed here...)
As I told DerVVulfman last night RMXP's solution for map scrolling would NOT work on KUnits Gosu, that truth hasn't changed, BUT some creativity was needed to solve this mystery. I had partially found a way to solve it.

# Pressing Down Arrow
@offset_y = [-@screen_y + 608 / 1.08, 0].min# Works but only if you hit the lower edge of the game window then you'd make it scroll

# Pressing Right Arrow
@offset_x = [-@screen_x + 800 / 1.042, 0].min# Works but only if you hit the right edge of the game window then you'd make it scroll

Don't ask me why they had to be those values or else the minimum command wouldn't ever work! (I tried replacing the screen coordinate plus the dimension divided by a weird value with an 8, it automatically chose 0 as result, changing it to max became a new nightmare! The map either got scrolled to the left hand side almost EXPONENTIALLY or a sign change in reverted it by pushing the map to the right hand side making it arrive in Japan!)

But there's always a catch...

What if in some case like when the offset is decreasing (by adding 8 to its actual value) or the remainder (2px?) was possible in one situation? I started trying to make it work and it didn't take me long to noticed it was perfect... almost.

# Pressing Left Arrow
@offset_x += [8, -@offset_x].min if @offset_x < 0 and @screen_x - @offset_x < Map.width * 32

Yes, every single tile is 32 pixels wide and high as well. Multiplying the corresponding dimension sounds quite logical... but not to my beloved Ruby Gosu engine! It made the player vanish unless IT, not the player's sprite character, got close to the left edge of the game window. Then I thought I had to define it as Map.width * 16 so it would only do it if the offset was less than half the current map's width... It messed it up as well.

After several attempts I found out the perfect value HAD to be 23.5 and it would work on ANY map that was larger than the minimum width (25 tiles * 32 pixels). Minimum sized maps wouldn't complain at all.

I still had a serious issue to solve, how could I make it stop waiting for the sprite to hit the opposite edge before it scrolled right? (Or to the right hand side?) I wasn't slow at all, I quickly thought a conditional statement would take care of that important job! I was WRONG! I messed up once again!

Then I had a clever idea, what if the solution I applied to it's opposite direction had a clue on what to do to fix the latter?

@offset_x -= [-8, @offset_x].min if @offset_x < 0 and @screen_x - @offset_x > Map.width * 26 # Yeah I first tried with 26 for a reason I've forgotten...

How weird! It didn't help me, the screen jumped suddenly without warning! How crappy!

Nope, 0 would make the jump look even more extreme, as much as to beat any X-Gamer while trying to break his bones while flying briefly in the air before dropping onto the floor hitting his legs or arms hard against it...

There was a revelation finally! I had to modify it slightly so it would actually help me there solving my issue.

@offset_x = [@offset_x - 8, @offset_x-@offset_x].min if @offset_x < 0 and @screen_x - @offset_x > Map.width * 26

Got close... but not enough to what people would actually expect, something was missing...

Gotcha! I had to include a calculation included in XP, that's all I had to do!

@offset_x = [[@offset_x - 8, @offset_x-@offset_x].min, (Map.width - 25) * 32].max if @offset_x < 0 and @screen_x - @offset_x > Map.width * 26

It should work fine now for sure, I took into account that Gosu has no such real_x coordinates so I had to multiply it by the actual tile width. Wait a minute! Where did my stupid map go? It looked like it did break through to the other side, whatever that was!

After a while I had found an "imperfect solution", but it WAS a solution after all!

@offset_x = [[@offset_x - 8, @offset_x-@offset_x].min, -(Map.width - 25) * 32].max if @offset_x < 0 and @screen_x - @offset_x > Map.width * 26

Say what? "How's that gonna help you at all?" you may ask me now. Well, it sure did! Yeah, I DO mean it! It took it a few more pixels to react than expected but no signs of oblivion was ever seen!

But how could I make it react soon enough as if I had gone through an invisible trigger right in the middle of the game window? That was the moment when I started fiddling with the map width value by increasing or decreasing it over and over again...

@offset_x = [[@offset_x - 8, @offset_x-@offset_x].min, -(Map.width - 25) * 32].max if @offset_x < 0 and @screen_x - @offset_x > Map.width * 12.75

Yeah! I DID IT! I still don't know what the best value was 12.75, but it sure works fine!

And for a while this early morning (like till 2 o'clock) I was happy with the result until I found out something was missing there...

No, wait a second! My second scripting epiphany had arrived! A missing part was not the ACTUAL issue here, but an extra part was indeed!

@offset_x = [@offset_x - 8, -(Map.width - 25) * 32].max if @offset_x < 0 and @screen_x - @offset_x > Map.width * 12.75

Yeah, guys, the part inbetween was completely useless at that point...

Hold on! I clearly stated earlier that XP didn't help me there at all, didn't I? And you know what, I wasn't lying, I just ignored why it didn't and never would. My solution was completely customized and that's how it should have been from the very beginning!

But what did I do?

First of all it's not that similar, I don't call the map to get any scrolling variable, and I skipped any unnecessary calculations and I never ADD the current distance, which is easily determined in my project, it's always 8 (most of the time ). Oh and I substract the extra tiles width as well!

MYSTERY SOLVED! Ruby Gosu does never add distance to move everything on screen, it substract all values in a flip!

Solving the issue with the map's height was no problem at all! A real piece of cake!

Was it?

Take a look at the actual scrolling code and see by yourself if that was an accurate statement or not.

Code:
```class Player   def update    return if @halt    @last_x = @screen_x    @last_y = @screen_y    return if moved?    if Gosu.button_down?(Gosu::KbDown)      @dir = @other_way ? 8 : 2      return unless pass?      @y += 0.5      @screen_y = @y * 16      @offset_y = [@offset_y - 8, -(Map.height - 19) * 32].max if @screen_y > Map.height * 8      update_steps    elsif Gosu.button_down?(Gosu::KbUp)      @dir = @other_way ? 2 : 8      return unless pass?      @y -= 0.5      @screen_y = @y * 16      @offset_y += [8, -@offset_y].min if @offset_y < 0 and @screen_y - @offset_y < Map.height * 32      update_steps    elsif Gosu.button_down?(Gosu::KbLeft)      @dir = @other_way ? 6 : 4      return unless pass?      @x -= 0.5      @screen_x = @x * 16      @offset_x += [8, -@offset_x].min if @offset_x < 0 and @screen_x - @offset_x < Map.width * 23.5      update_steps    elsif Gosu.button_down?(Gosu::KbRight)      @dir = @other_way ? 4 : 6      return unless pass?      @x += 0.5      @screen_x = @x * 16      @offset_x = [@offset_x - 8, -(Map.width - 25) * 32].max if @screen_x > Map.width * 12.75      update_steps    end    if button_down?(:enter) or button_down?(:return)      Map.events.each do |event|      blocked = block_pass?(event)      next unless blocked      event.react_now if event.react      if event.button?        event.activate        @halt = true        return      end    end   end end class SceneMap   def update_scene     if @map_ticks > 0       @map_ticks -= 1       @map_texts.clear if @map_ticks == 0     end     @player.update     @offset_x = @player.offset_x     @offset_y = @player.offset_y     Map.events.each {|e| e.update }     @spriteset.update     if press_quit?       Game.cancel_se.play       Game.setup(SceneKUnitsMenu)       return     elsif button_down?(:left_ctrl)       Game.ok_se.play       Game.setup(SceneKUnitsAchieve)     elsif button_down?(:caps_lock)       Game.ok_se.play       Game.setup(SceneKUnitsFoes)     elsif button_down?(:left_shift)       Game.ok_se.play       Game.setup(SceneKBookPages, id: 1)     end   end   def draw     @window.clip_to(0,0,@window_width,@window_height) do       @window.translate(@offset_x,@offset_y) do         @spriteset.draw       end     end     @map_texts.each {|text| text.draw }   end end```