Map scrolling nightmare...
#1
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.)

[Image: QXTKpxr.png]

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

[Image: 2LgGaEr.png]


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.
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#2
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. Shocked

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! Ticked off 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! Happy with a sweat

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! Very happy + Tongue sticking out 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... Confused

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! Ticked off Where did my stupid map go? It looked like it did break through to the other side, whatever that was! Feeling sick

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? Happy with a sweat "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! Winking I still don't know what the best value was 12.75, but it sure works fine! Laughing + Tongue sticking out

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... Indifferent

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

@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... Happy with a sweat

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! Shocked

But what did I do? Sarcasm

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 Laughing + Tongue sticking out ). 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! Shocked

Solving the issue with the map's height was no problem at all! A real piece of cake! Very happy + Tongue sticking out

Was it? Confused

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
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }


Possibly Related Threads…
Thread Author Replies Views Last Post
   Cursor, Selection, and Scrolling tnsi 7 10,748 01-10-2012, 04:16 AM
Last Post: DerVVulfman



Users browsing this thread: 1 Guest(s)