Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Can't Jump into a gap / hole... :/

Good day everybody!

During my recent revision of my test bed (which I haven't updated in months...) there's one problem in one script I've never been able to overcome. I suppose this little bug could be a big deal depending on what certain people really wanted to use the script for. The problem I'm talking about is the player can jump over X ammount of spaces (whatever the farthest space is) yet... I can't get the player to jump between objects, like so...

O O X O X

The O's 'n X's represent passability like the passabilities setup in the tileset editor. See the space between the two X's (impassable tiles), the player would be able to jump out of that spot, but if I wanted him to jump back in it wouldn't work. The method that defines this is Game_Player#jump_dist, which basically iterates from Jump::Dist downto 0 and passable spaces into an array, then returns array.first or whatever

Code:
  #-----------------------------------------------------------------------------
  # * Jump Dist
  #-----------------------------------------------------------------------------
  def jump_dist
    spaces = Array.new
    (Jump::Distance).downto(0) do |i|
      if SDK.enabled?('Player.Run') && Object.const_defined?(:Run)
        i += Jump.run_modifier if $game_player.running?
      end
      i -= 1 if attempt_diagonal? || moving_diagonal?
      j = i + 1
      case move_direction
      when 1 ; spaces.push(j) if passable?(self.x-i, self.y+i, 0)
      when 3 ; spaces.push(j) if passable?(self.x+i, self.y+i, 0)
      when 7 ; spaces.push(j) if passable?(self.x-i, self.y-i, 0)
      when 9 ; spaces.push(j) if passable?(self.x+i, self.y-i, 0)
      end
      case @direction
      when 2 ; spaces.push(j) if passable?(self.x,   self.y+i, @direction)
      when 4 ; spaces.push(j) if passable?(self.x-i, self.y,   @direction)
      when 6 ; spaces.push(j) if passable?(self.x+i, self.y,   @direction)
      when 8 ; spaces.push(j) if passable?(self.x,   self.y-i, @direction)
      end
    end
    return spaces.empty? ? 0 : spaces.first
  end

Here's the full copy of the script, you might want to playtest it yourself 'n see if you can figure out why I'm having this problem because the code looks fine to the naked eye but perhaps there's something I'm just totally overlooking...

Code:
#===============================================================================
# ~** Character Move Test **~
#-------------------------------------------------------------------------------
# Written By  : Kain Nobel
# Version     : 2.0
# Last Update : 09.02.2008
#===============================================================================
# Description
# -----------
#
#   This is a special set of methods, that will tell you which direction a
#   character or event is moving, and supports both 4 and 8 directional movement
#   checking.
#
#   When checking something like $game_map.events[1].moving_down?, you have the
#   optional argument 'diag'. If you set this argument as 'true' and a player is
#   moving_lower_left, then it'll return false, else it'll return true for both.
#
#   Also, for Game_Player, we've got additional methods for checking if player
#   is 'attempting' to move a certain direction. This is for scripts that want
#   to know, "Is he just 'attempting' to move left, or is he 'really' moving
#   left? So, it doesn't check for Input, rather it'll check for Movement AND
#   Input.
#
# Methods List
# -------------
# Game_Character
#   moving_down?
#   moving_left?
#   moving_right?
#   moving_up?
#   moving_upper_left?
#   moving_upper_right?
#   moving_lower_left?
#   moving_lower_right?
#   move_direction
#   moving_diagonal?
#
# Game_Player (< Game_Character)
#   attempt_down?
#   attempt_left?
#   attempt_right?
#   attempt_up?
#   attempt_upper_left?
#   attempt_upper_right?
#   attempt_lower_left?
#   attempt_lower_right?
#   attempt_moving?
#   attempt_direction?
#   attempt_diagonal?
#
#===============================================================================
#-------------------------------------------------------------------------------
# * SDK Log
#-------------------------------------------------------------------------------
if Object.const_defined?(:SDK)
  SDK.log('MACL::RGSS.Character.MoveTest', 'Kain Nobel', 2.0, '09.21.2008')
end
#-------------------------------------------------------------------------------
# * MACL Loading
#-------------------------------------------------------------------------------
if Object.const_defined?(:MACL)
  MACL::Loaded << 'RGSS.Character.MoveTest'
end
#===============================================================================
# ** Game_Character
#-------------------------------------------------------------------------------
#   The parent superclass of Game_Player and Game_Event has been modified to
# return detailed information on which direction a character is moving.
#===============================================================================
class Game_Character
  #-----------------------------------------------------------------------------
  # * Moving Down?
  #-----------------------------------------------------------------------------
  def moving_down?(diag = false)
    return false if !diag && (moving_lower_left? || moving_lower_right?)
    return (self.real_y < self.y * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Left?
  #-----------------------------------------------------------------------------
  def moving_left?(diag = false)
    return false if !diag && (moving_upper_left? || moving_lower_left?)
    return (self.real_x > self.x * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Right?
  #-----------------------------------------------------------------------------
  def moving_right?(diag = false)
    return false if !diag && (moving_upper_right? || moving_lower_right?)
    return (self.real_x < self.x * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Left?
  #-----------------------------------------------------------------------------
  def moving_up?(diag = false)
    return false if !diag && (moving_upper_left? || moving_upper_right?)
    return (self.real_y > self.y * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Lower Left?
  #-----------------------------------------------------------------------------
  def moving_lower_left?
    return (self.real_y < self.y * 128) && (self.real_x > self.x * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Lower Right?
  #-----------------------------------------------------------------------------
  def moving_lower_right?
    return (self.real_y < self.y * 128) && (self.real_x < self.x * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Lower Left?
  #-----------------------------------------------------------------------------
  def moving_upper_left?
    return (self.real_y > self.y * 128) && (self.real_x > self.x * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Lower Right?
  #-----------------------------------------------------------------------------
  def moving_upper_right?
    return (self.real_y > self.y * 128) && (self.real_x < self.x * 128)
  end
  #-----------------------------------------------------------------------------
  # * Move Direction?
  #-----------------------------------------------------------------------------
  def move_direction
    return 2 if moving_down?  && !(moving_lower_left?   || moving_lower_right?)
    return 4 if moving_left?  && !(moving_lower_left?   || moving_upper_left?)
    return 6 if moving_right? && !(moving_lower_right?  || moving_upper_right?)
    return 8 if moving_up?    && !(moving_upper_left?   || moving_upper_right?)
    return 1 if moving_lower_left?
    return 3 if moving_lower_right?
    return 7 if moving_upper_left?
    return 9 if moving_upper_right?
    return 0
  end
  #-----------------------------------------------------------------------------
  # * Moving Diagonal?
  #-----------------------------------------------------------------------------
  def moving_diagonal?
    return true if moving_upper_left? or moving_upper_right?
    return true if moving_lower_left? or moving_lower_right?
    return false
  end
  #-----------------------------------------------------------------------------
  # * Attempt Print Test
  #-----------------------------------------------------------------------------
  def moving_print_test(diag = false)
    print("Down : "+moving_down?(diag).to_s+
    "\nLeft : "+moving_left?(diag).to_s+
    "\nRight : "+moving_right?(diag).to_s+
    "\nUp : "+moving_up?(diag).to_s+
    "\nUpRight : "+moving_upper_right?.to_s+
    "\nUpLeft : "+moving_upper_left?.to_s+
    "\nDownRight : "+moving_lower_right?.to_s+
    "\nDownLeft : "+moving_lower_left?.to_s+
    "\nDirection : "+move_direction.to_s)
  end
end

#===============================================================================
# ** Game_Player
#-------------------------------------------------------------------------------
#   The child class of Game_Character, returns user's directional input to tell
# you if they're 'attemtping' to move a certain direction.
#===============================================================================
class Game_Player < Game_Character
  #-----------------------------------------------------------------------------
  # * Attempt Down?
  #-----------------------------------------------------------------------------
  def attempt_down?(diag = false)
    unless Input.press?(Input::LEFT) || Input.press?(Input::RIGHT)
      return Input.press?(Input::DOWN)
    end ; return false
  end
  #-----------------------------------------------------------------------------
  # * Attempt Left?
  #-----------------------------------------------------------------------------
  def attempt_left?(diag = false)
    unless Input.press?(Input::UP) || Input.press?(Input::DOWN)
      return Input.press?(Input::LEFT)
    end ; return false
  end
  #-----------------------------------------------------------------------------
  # * Attempt Right?
  #-----------------------------------------------------------------------------
  def attempt_right?(diag = false)
    unless Input.press?(Input::UP) || Input.press?(Input::DOWN)
      return Input.press?(Input::RIGHT)
    end ; return false
  end
  #-----------------------------------------------------------------------------
  # * Attempt Up?
  #-----------------------------------------------------------------------------
  def attempt_up?(diag = false)
    unless Input.press?(Input::LEFT) || Input.press?(Input::RIGHT)
      return Input.press?(Input::UP)
    end ; return false
  end
  #-----------------------------------------------------------------------------
  # * Attempt Upper Left?
  #-----------------------------------------------------------------------------
  def attempt_upper_left?
    m = Input.press?(Input::UP) && Input.press?(Input::LEFT)
    if defined?(Aleworks) && !m
      return Input.press?(Input::UPPER_LEFT) 
    end
    return m
  end
  #-----------------------------------------------------------------------------
  # * Attempt Upper Right?
  #-----------------------------------------------------------------------------
  def attempt_upper_right?
    m = Input.press?(Input::UP) && Input.press?(Input::RIGHT)
    if defined?(Aleworks) && !m
      return Input.press?(Input::UPPER_RIGHT)
    end
    return m
  end
  #-----------------------------------------------------------------------------
  # * Attempt Lower Left?
  #-----------------------------------------------------------------------------
  def attempt_lower_left?
    m = Input.press?(Input::DOWN) && Input.press?(Input::LEFT)
    if defined?(Aleworks) && !m
      return Input.press?(Input::LOWER_LEFT)
    end
    return m
  end
  #-----------------------------------------------------------------------------
  # * Attempt Lower Right?
  #-----------------------------------------------------------------------------
  def attempt_lower_right?
    m = Input.press?(Input::DOWN) && Input.press?(Input::RIGHT)
    if defined?(Aleworks) && !m
      return Input.press?(Input::LOWER_RIGHT)
    end
    return m
  end
  #-----------------------------------------------------------------------------
  # * Attempt Moving?
  #-----------------------------------------------------------------------------
  def attempt_moving?(diag = false)
    return true if attempt_down?(diag)
    return true if attempt_left?(diag)
    return true if attempt_right?(diag)
    return true if attempt_up?(diag)
    return attempt_diagonal?
  end
  #-----------------------------------------------------------------------------
  # *  Attempt Direction
  #-----------------------------------------------------------------------------
  def attempt_direction?
    if    attempt_down?         ; return 2
    elsif attempt_left?         ; return 4
    elsif attempt_right?        ; return 6
    elsif attempt_up?           ; return 8
    elsif attempt_lower_left?   ; return 1
    elsif attempt_lower_right?  ; return 3
    elsif attempt_upper_left?   ; return 7
    elsif attempt_upper_right?  ; return 9
    else                        ; return 0
    end
  end
  #-----------------------------------------------------------------------------
  # * Attempt Diagonal?
  #-----------------------------------------------------------------------------
  def attempt_diagonal?
    return true if attempt_upper_left?
    return true if attempt_upper_right?
    return true if attempt_lower_left?
    return true if attempt_lower_right?
    return false
  end
  #-----------------------------------------------------------------------------
  # * Attempt Print Test
  #-----------------------------------------------------------------------------
  def attempt_print_test(diag = false)
    print("Down : "+attempt_down?(diag).to_s+
    "\nLeft : "+attempt_left?(diag).to_s+
    "\nRight : "+attempt_right?(diag).to_s+
    "\nUp : "+attempt_up?(diag).to_s+
    "\nUpRight : "+attempt_upper_right?.to_s+
    "\nUpLeft : "+attempt_upper_left?.to_s+
    "\nDownRight : "+attempt_lower_right?.to_s+
    "\nDownLeft : "+attempt_lower_left?.to_s)
  end
end
Code:
#===============================================================================
# ** Player.Jump
#===============================================================================

#-------------------------------------------------------------------------------
# * SDK Log
#-------------------------------------------------------------------------------
SDK.log('Player.Jump', 'Kain Nobel ©', 2.0, '11.01.2008')
#-------------------------------------------------------------------------------
# * SDK Enabled Test - BEGIN
#-------------------------------------------------------------------------------
if SDK.enabled?('Player.Jump')

#===============================================================================
# ** Jump
#===============================================================================

module Jump
################################################################################
# ~**                CUSTOMIZABLE CONSTANTS - BEGIN                        **~ #
################################################################################
  #-----------------------------------------------------------------------------
  # * IDs of Maps which you aren't allowed to jump
  #-----------------------------------------------------------------------------
  Xclude_Maps   = []
  #-----------------------------------------------------------------------------
  # * Distance (in tiles) that you regularly jump
  #-----------------------------------------------------------------------------
  Distance      = 3
  #-----------------------------------------------------------------------------
  # * Are you able to jump over objects with Counter tags on them?
  #-----------------------------------------------------------------------------
  Counter_Pass  = false
  #-----------------------------------------------------------------------------
  # * Jump Bonus gained from running (If using Run Script)
  #-----------------------------------------------------------------------------
  Run_Modifier  = 1
  #-----------------------------------------------------------------------------
  # * Audiofile to be played when you jump
  #-----------------------------------------------------------------------------
  SE_Jump       = RPG::AudioFile.new("015-Jump01", 80, 90)
  #-----------------------------------------------------------------------------
  # * Audofile to be played when you land
  #-----------------------------------------------------------------------------
  SE_Land       = RPG::AudioFile.new("016-Jump02", 80, 90)
  #-----------------------------------------------------------------------------
  # * Input/Key to be used to trigger the player to jump
  #-----------------------------------------------------------------------------
  Button        = Keys::SHIFT
  #-----------------------------------------------------------------------------
  # * Does jumping repeat when you hold the Button?
  #-----------------------------------------------------------------------------
  Repeat        = false
################################################################################
# ~**                 CUSTOMIZABLE CONSTANTS - END                         **~ #
################################################################################
  #-----------------------------------------------------------------------------
  # * Jump.play_audiofile
  #-----------------------------------------------------------------------------
  def self.play_audiofile(se)
    case se.class.to_s
    when "RPG::AudioFile"
      unless se.name.include?("Audio/SE/")
        se.name = "Audio/SE/" + se.name
      end
      Audio.se_play(se.name, se.volume, se.pitch)
    when "String"
      unless se.include?("Audio/SE/")
        se = "Audio/SE/" + se
      end
      Audio.se_play(se, 100, 100)
    when "Array"
      n = se.size > 0 ? se[0] : ""
      v = se.size > 1 ? se[1] : 100
      p = se.size > 2 ? se[2] : 100
      unless n.include?("Audio/SE/")
        n = "Audio/SE/" + n
      end
      Audio.se_play(n, v, p)
    end
    return RPG::AudioFile.new
  end
  #-----------------------------------------------------------------------------
  # * Jump.se_jump
  #-----------------------------------------------------------------------------
  def self.se_jump
    return play_audiofile(SE_Jump)
  end
  #-----------------------------------------------------------------------------
  # * Jump.se_land
  #-----------------------------------------------------------------------------
  def self.se_land
    return play_audiofile(SE_Land)
  end
  #-----------------------------------------------------------------------------
  # * Jump.xclude_map?
  #-----------------------------------------------------------------------------
  def self.xclude_map?
    xclude = Xclude_Maps.is_a?(Array) ? Xclude_Maps : []
    return xclude.include?($game_map.map_id)
  end
  #-----------------------------------------------------------------------------
  # * Jump.run_modifier
  #-----------------------------------------------------------------------------
  def self.run_modifier
    return Run_Modifier.is_a?(Numeric) ? Run_Modifier : 0
  end
end

#===============================================================================
# ** Game_Map
#===============================================================================

class Game_Map
  #-----------------------------------------------------------------------------
  # * Tile Blank?
  #-----------------------------------------------------------------------------
  def no_tile?(x, y)
    [2, 1, 0].each do |i|
      return true if data[x, y, i].nil?
    end
    return data[x, y, 2].zero? && data[x, y, 1].zero? && data[x, y, 0].zero?
  end
  #-----------------------------------------------------------------------------
  # * Disable Dash?
  #-----------------------------------------------------------------------------
  def disable_jump?
    return Jump::XcludeMaps.include?(@map_id)
  end
end

#===============================================================================
# ** Game_Character
#===============================================================================

class Game_Character
  #-----------------------------------------------------------------------------
  # * Alias Listings
  #-----------------------------------------------------------------------------
  alias_method :character_jump,         :jump
  alias_method :character_update_jump,  :update_jump
  alias_method :no_tile_passable?,      :passable?
  #-----------------------------------------------------------------------------
  # * Jump
  #-----------------------------------------------------------------------------
  def jump(x_plus, y_plus)
    Jump.se_jump
    character_jump(x_plus, y_plus)
  end
  #-----------------------------------------------------------------------------
  # * Update Jump
  #-----------------------------------------------------------------------------
  def update_jump
    character_update_jump
    if @jump_count.zero?
      Jump.se_land
    end
  end
  #-----------------------------------------------------------------------------
  # * Passable?
  #-----------------------------------------------------------------------------
  def passable?(x, y, d)
    new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
    new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
    return $game_map.no_tile?(new_x, new_y) ? false : no_tile_passable?(x, y, d)
  end
end

#===============================================================================
# ** Game_Player
#===============================================================================

class Game_Player < Game_Character
  #-----------------------------------------------------------------------------
  # * Alias Listings
  #-----------------------------------------------------------------------------
  alias_method :jump_player_update,         :update
  #-----------------------------------------------------------------------------
  # * Update
  #-----------------------------------------------------------------------------
  def update
    jump_player_update
    unless Jump.xclude_map? || jumping? || !jump_valid?
      if Jump::Repeat ? Input.press?(Jump::Button) : Input.trigger?(Jump::Button)
        case @direction
        when 2 # Jump Down  / Down-Left || Down-Right
          if    attempt_lower_left?   ; jump(-(jump_dist-1), (jump_dist-1))
          elsif attempt_lower_right?  ; jump((jump_dist-1), (jump_dist-1))
          else                        ; jump(0, jump_dist)
          end
        when 4 # Jump Left  / Up-Left   / Down-Left
          if    attempt_upper_left?   ; jump(-(jump_dist-1), -(jump_dist-1))
          elsif attempt_lower_left?   ; jump(-(jump_dist-1), (jump_dist-1))
          else                        ; jump(-jump_dist, 0)
          end
        when 6 # Jump Right / Up-Right  / Down-Right
          if    attempt_upper_right?  ; jump((jump_dist-1), -(jump_dist-1))
          elsif attempt_lower_right?  ; jump((jump_dist-1), (jump_dist-1))
          else                        ; jump(jump_dist, 0)
          end
        when 8 # Jump Up    / Up-Left   / Up-Right
          if    attempt_upper_left?   ; jump(-(jump_dist-1), -(jump_dist-1))
          elsif attempt_upper_right?  ; jump((jump_dist-1), -(jump_dist-1))
          else                        ; jump(0, -jump_dist)
          end
        end
      end
    end
  end
  #-----------------------------------------------------------------------------
  # * Jump Valid ?
  #-----------------------------------------------------------------------------
  def jump_valid?
    return $DEBUG if Input.press?(Input::CTRL)
    case move_direction
    when 1
      return false if self.y > $game_map.height - Jump::Distance
      return false if self.x < Jump::Distance
    when 3
      return false if self.y > $game_map.height - Jump::Distance
      return false if self.x > $game_map.width  - Jump::Distance
    when 7
      return false if self.y < Jump::Distance
      return false if self.x > $game_map.width  - Jump::Distance 
    when 9
      return false if self.y < Jump::Distance
      return false if self.x < Jump::Distance
    end
    case @direction
    when 2 ; return false if self.y > $game_map.height - Jump::Distance
    when 4 ; return false if self.x < Jump::Distance
    when 6 ; return false if self.x > $game_map.width  - Jump::Distance
    when 8 ; return false if self.y < Jump::Distance
    end
    unless Jump::Counter_Pass == true
      0.upto(Jump::Distance) do |i|
        case move_direction
        when 1 ; return false if $game_map.counter?(self.x-i, self.y+i)
        when 3 ; return false if $game_map.counter?(self.x+i, self.y+i)
        when 7 ; return false if $game_map.counter?(self.x-i, self.y-i)
        when 9 ; return false if $game_map.counter?(self.x+i, self.y-i)
        end
        case @direction
        when 2 ; return false if $game_map.counter?(self.x, self.y+i)
        when 4 ; return false if $game_map.counter?(self.x-i, self.y)
        when 6 ; return false if $game_map.counter?(self.x+i, self.y)
        when 8 ; return false if $game_map.counter?(self.x, self.y-i)
        end
      end
    end
    return true
  end
  #-----------------------------------------------------------------------------
  # * Jump Dist
  #-----------------------------------------------------------------------------
  def jump_dist
    spaces = Array.new
    (Jump::Distance).downto(0) do |i|
      if SDK.enabled?('Player.Run') && Object.const_defined?(:Run)
        i += Jump.run_modifier if $game_player.running?
      end
      i -= 1 if attempt_diagonal? || moving_diagonal?
      j = i + 1
      case move_direction
      when 1 ; spaces.push(j) if passable?(self.x-i, self.y+i, 0)
      when 3 ; spaces.push(j) if passable?(self.x+i, self.y+i, 0)
      when 7 ; spaces.push(j) if passable?(self.x-i, self.y-i, 0)
      when 9 ; spaces.push(j) if passable?(self.x+i, self.y-i, 0)
      end
      case @direction
      when 2 ; spaces.push(j) if passable?(self.x,   self.y+i, @direction)
      when 4 ; spaces.push(j) if passable?(self.x-i, self.y,   @direction)
      when 6 ; spaces.push(j) if passable?(self.x+i, self.y,   @direction)
      when 8 ; spaces.push(j) if passable?(self.x,   self.y-i, @direction)
      end
    end
    return spaces.empty? ? 0 : spaces.first
  end
end

#-------------------------------------------------------------------------------
# * SDK Enabled Test - END
#-------------------------------------------------------------------------------
end

Setup a test map similar to this one and test it from different directions (they should all work the same, diagonals lose 1 space of distance when jumping though naturally). You'll see, based on what you set Jump::Distance to, the player can jump out but can never jump back in.

http://i224.photobucket.com/albums/dd288/Kain_Nobel/JumpTest.png[/img]
 

Atoa

Member

Try use terrain tags to overcome this.
If the blocked tile has the terrain tag, and the jump distance is enough to pass over it the jumps work.

Or you could do something like MGCaladtogel Moving Plataforms, where holes are passable, but if you "fell" on it, the script calls an common event.
 
You might want to check out how event based character jumping is handled in the default scripts. I just tested the center of your map with events, and you can jump both in and out of it. Also, the scripts are the same in both spoilers.
 
Fixed post. I'd hope it works with events, but it doesn't work with my script I can't jump in between of objects :P

The only thing that should effect the player being able to jump there is if it was too far for him to jump and/or any of the objects between point A and B had a counter tag (because I use all my terrain tags for another script)
 
I think I found your problem
Code:
# If unable to leave first move tile in designated direction
    unless $game_map.passable?(x, y, d, self)
      # impassable
      return false
    end

In the original passable? method for Game_Character, it makes a check to see if the tile you're moving to is passable from the tile adjacent to it in the source direction. This means

O 1 2 X 4
(O is player, X is block tiles, numbers are destinations)

4 is not open because you can't get there from the tile before it, so you jump to 2.
So you'll need to make jumping direction insensitive, or rewrite passable? instead of aliasing it.
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top