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.

Journal pictures

I made an add-on to a journal script I was using so it will display a picture for each quest that's in the journal. However, if I leave the game running for a few minutes, the game will crash and say 'failed to create bitmap.' Here is the code for the picture part of the journal:

Code:
#==============================================================================
# ** Journal
#------------------------------------------------------------------------------
#  This window displays a journal.
#==============================================================================

class Window_JournalRight < Window_Base
# ------------------------

attr_accessor :index
attr_accessor :quest_size

def initialize
  
   # Offset - enter the offset to the first variable you are using
   # This is one less than the variable number.
   
   @offset = 0
   
   @questpic = []
   @questpic[0] = '/journal/quest_default.png'
   @questpic[1] = '/journal/farm.png'
   @questpic[2] = '/journal/farm2.png'
   @questpic[3] = '/journal/farm3.png'
   
   super(0, 32, 460, 640) 
 
   @index = 0 
   @quest_size = @questpic.size

         @testpic = RPG::Sprite.new 
  
   refresh

 end


#--------------------------------------------------------------------------
# * Draw the contents of the item window
#--------------------------------------------------------------------------

  def refresh
     
 #        @testpic.visible = false
#    self.contents.clear
    
    for i in @index..@questpic.size - 1
      if $game_variables[i + @offset] > 0
        
        
     @testpic.bitmap = Bitmap.new("Graphics/Pictures" + @questpic[i])
     @testpic.x = 350
     @testpic.visible = true
        
        @index = i
        break
      end
    end  
    if @index == 0
      
     @testpic.bitmap = Bitmap.new("Graphics/Pictures" + @questpic[0])
     @testpic.x = 350
     @testpic.visible = true

    end
  end
end


end

If I try to clear the sprite (where I commented out  # @testpic.visible = false and #self.contents.clear) then the image won't show up at all. So I don't know if clearing the sprite everytime it refreshes has something to do with the game crashing if it stays on that journal screen with the pictures for a long time or not. I'm not sure what else I can do to keep the pictures form overloading like that...
 

khmp

Sponsor

You need to dispose of the resource and then I think the rest is good.

So add in this method:

Code:
  def dispose
    super()
    @testpic.bitmap.dispose unless @testpic.bitmap.disposed?
    @testpic.dispose unless @testpic.disposed?
  end

Good luck with it Xathia Vastar! :thumb:
 

khmp

Sponsor

You throw the dispose method into your window class.

Code:
#==============================================================================
# ** Journal
#------------------------------------------------------------------------------
#  This window displays a journal.
#==============================================================================

class Window_JournalRight < Window_Base
# ------------------------

attr_accessor :index
attr_accessor :quest_size

def initialize
  
   # Offset - enter the offset to the first variable you are using
   # This is one less than the variable number.
   
   @offset = 0
   
   @questpic = []
   @questpic[0] = '/journal/quest_default.png'
   @questpic[1] = '/journal/farm.png'
   @questpic[2] = '/journal/farm2.png'
   @questpic[3] = '/journal/farm3.png'
   
   super(0, 32, 460, 640) 
 
   @index = 0 
   @quest_size = @questpic.size

         @testpic = RPG::Sprite.new 
  
   refresh

 end


#--------------------------------------------------------------------------
# * Draw the contents of the item window
#--------------------------------------------------------------------------

  def refresh
     
 #        @testpic.visible = false
#    self.contents.clear
    
    for i in @index..@questpic.size - 1
      if $game_variables[i + @offset] > 0
        
        
     @testpic.bitmap = Bitmap.new("Graphics/Pictures" + @questpic[i])
     @testpic.x = 350
     @testpic.visible = true
        
        @index = i
        break
      end
    end  
    if @index == 0
      
     @testpic.bitmap = Bitmap.new("Graphics/Pictures" + @questpic[0])
     @testpic.x = 350
     @testpic.visible = true

    end
  end
end

  def dispose
    super
    @testpic.bitmap.dispose unless @testpic.bitmap.disposed?
    @testpic.dispose unless @testpic.disposed?
  end
end

Actually now that I take a closer look what are you trying to do in that Refresh method? Let's say you have this window appear in Scene_Whatever at the beginning of Scene_Whatever's main you would have a line like this:

Code:
@journal_window = Window_JournalRight.new

At the bottom of main you need to dispose of the window.

Code:
@journal_window.dispose

How are you currently presenting this window to the user?
 
okay, here is the whole journal script:

Code:
#==============================================================================
# â–  Scene_Journal
#------------------------------------------------------------------------------
#  This class contains the windows for the quest menu 
#  To access from the menu, insert $scene = Scene_Journal.new in your menu
#
#  Brewmeister - V10MAR08
#  Props to Lambchop (original creator) & Trickster (draw_wrap_text method)
#==============================================================================

class Scene_Journal
  #--------------------------------------------------------------------------
  # â—
 

khmp

Sponsor

Now I'm even more confused. The disposal code gives you an error there? Did Trickster and the other guy mentioned make the window classes as well?

I never did explain the bitmap error did I? Which was your initial problem. Ok so RMXP has a memory pool over which a lifeguard sits, known as (GC, Garbage Collection) who, periodically asks "Is that needed?" No? Alright send it back to the pool of memory thats free. If the answer is yes it just moves right along. When you create too many sprites or too many bitmaps you run the chance of the pool emptying completely. What's happening in your case is that no one is being sent back to the pool because none of the assets you allocate inside that window are returned to the pool.

If you change that dispose method to this:
Code:
  def dispose
    super
    @testpic.bitmap.dispose
    @testpic.dispose
  end
Do you get an error about nil class?
 
khmp":1uzftmzg said:
If you change that dispose method to this:
Code:
  def dispose
    super
    @testpic.bitmap.dispose
    @testpic.dispose
  end
Do you get an error about nil class?

yes.


btw, thank you for explaining that bitmap error. It makes sense to me. The problem is, I don't know how to fix it.
 

khmp

Sponsor

Well let's use the Cache instead of Bitmap.new in that window refresh then. This way the image only gets loaded once if it's unique.

Code:
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    # Clear the drawing surface
    self.contents.clear
    
    # Loop through each part of the picture string array
    for i in @index..@questpic.size - 1
      # If the quest exists
      if $game_variables[i + @offset] > 0
        
        # Create the quest's bitmap
        @testpic.bitmap = RPG::Cache.picture(@questpic[i])
        @testpic.x = 350
        @testpic.visible = true
        
        @index = i
        # We found a quest that's active? break.
        break
      end
    end
    
    # Why this part though?
    if @index == 0
      @testpic.bitmap = RPG::Cache.picture(@questpic[i])
      @testpic.x = 350
      @testpic.visible = true
    end
  end

Do you not draw anything on the window though?
 
Code:
    # Why this part though?
    if @index == 0
      @testpic.bitmap = RPG::Cache.picture(@questpic[i])
      @testpic.x = 350
      @testpic.visible = true
    end
  end

basically that is there as a default if there are no quests currently in the journal. When you select the journal option from the menu, if there are no active quests, then it will say: "You have no active quests in the journal" (from the Window_Journal class) and there will be a picture that shows up to correspond to this (in the Window_JournalRight class).

Each time you scroll through the journal entries with the arrow keys, the picture should change also to correspond with the quest that changes. That's what I was trying to do. I hope that makes sense.

When I put "self.contents.clear" right after "def refresh," the picture will show up for a split second then disappear and won't appear anymore.
 

khmp

Sponsor

Try this code. There's so much in the system that I would want to rewrite it but I stopped myself as soon as it worked. The above code displays two windows, which overlap currently. The right one shows an icon. The left says for me that no quests have been completed.
 

khmp

Sponsor

I don't have the icons so I don't know. Its a mess to me. Is there only ever one quest for the user?

Let me try to understand the design.

This Window_Journal is supposed to contain all the quests that are "found" whether they complete or active or whatever?
Window_JournalRight displays an icon. And nothing else? Do we need Window_JournalRight for anything else but this icon?
Scene_Journal presents both windows.
 
No, the journal entries appear if the corresponding variables are turned on (set to 1). For the purposes of testing, I made a bunch of journal entries and set them to 1 then looked in my journal. When you press the up or down arrow keys you can scroll through each of the entries. I also wanted to make it so that a picture would show up for each corresponding entry using the Window_JournalRight class for the journal pictures.
 

khmp

Sponsor

I got it. Those pictures explained things a lot better. I'm making Window_JournalRight a sprite instead because it only shows a picture.

Here ya go:
Code:
#==============================================================================
# ** Quest Settings
#------------------------------------------------------------------------------
#  This module holds settings that are shared for all quest related items.
#==============================================================================

module Quest_Settings
  #--------------------------------------------------------------------------
  # * The quest names
  #--------------------------------------------------------------------------
  QUEST_NAMES = []
  
  QUEST_NAMES[0] = "Help Man"
  QUEST_NAMES[1] = "Kill Chicken"
  QUEST_NAMES[2] = "Make cow eat"
  QUEST_NAMES[3] = "Sniff the Glove"
  QUEST_NAMES[4] = "Jump off a bridge after your friends"
  QUEST_NAMES[5] = "Daily Chores"
  
  #--------------------------------------------------------------------------
  # * The quest descriptions
  #--------------------------------------------------------------------------
  QUEST_DESCS = []

  QUEST_DESCS[0] = "Help out the man."
  QUEST_DESCS[1] = "Kill a chicken & return it to Helga."
  QUEST_DESCS[2] = "Find an emaciated cow & feed it."
  QUEST_DESCS[3] = "Bark like a dog."
  QUEST_DESCS[4] = "Just to show long text: Funny story reverting back to " +
                   "childhood cliche, and a camping trip with my friends. " +
                   "Did they jump off a bridge? Yes, they did. Did I follow " +
                   "them? Of course I did!"
  QUEST_DESCS[5] = "Father wants Kaze and I to help \n" +
                   "him in the farm today. No doubt, it will be another " + 
                   "long and tiresome day in the fields again. I wonder " +
                   "what sort of job he will have us doing this time? " +
                   "He seems to always make me work the hardest, anyway. " +
                   "Let`s just get this over with so we can get some food " + 
                   "afterwards, eh?"
                   
  #--------------------------------------------------------------------------
  # * If the user has no quests this information will be displayed.
  #--------------------------------------------------------------------------
  QUEST_DEF_NAME = "Quest Log"
  QUEST_DEF_DESC = "You have no active or completed quests"
  
  #--------------------------------------------------------------------------
  # * The quest pictures
  #--------------------------------------------------------------------------             
  QUEST_PICS = []

  # Quest Pictures must be placed inside 'Graphics/Pictures/'
  QUEST_PIC_DIR = 'Journal/'
  QUEST_PICS[0] = 'quest_default.png'
  QUEST_PICS[1] = 'farm.png'
  QUEST_PICS[2] = 'farm2.png'
  QUEST_PICS[3] = 'farm3.png'
  
  #--------------------------------------------------------------------------
  # * Index offset into "$game_variables" for quest info.
  #--------------------------------------------------------------------------
  VARIABLE_OFFSET = 0

  #--------------------------------------------------------------------------
  # Just a safety precaution to make sure the user understands the amount
  # of quest names must equal the amount of the descriptions and vice versa.
  #--------------------------------------------------------------------------
  if QUEST_NAMES.size != QUEST_DESCS.size
    difference = (QUEST_NAMES.size - QUEST_DESCS.size).abs
    if QUEST_NAMES.size > QUEST_DESCS.size
      print("There are " + difference.to_s + " more quest names then there " +
        "are quest descriptions.")
    else
      print("There are " + difference.to_s + " more quest descriptions then " +
        "there are quest names.")
    end
  end
end

#==============================================================================
# ** Window_Journal
#------------------------------------------------------------------------------
#  This window displays a journal.
#==============================================================================

class Window_Journal < Window_Base
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :index
  attr_accessor :quests
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize
    
    super(0, 0, 460, 480)
    
    self.contents = Bitmap.new(width - 32, height - 32)
    
    # This array will contain all the quests that the user knows when this
    # window is created.
    @quests = []
    
    # Iterate through our quests
    for i in 0...Quest_Settings::QUEST_NAMES.size
      # If the quest has been turned on draw it.
      if $game_variables[i + Quest_Settings::VARIABLE_OFFSET] > 0
        # Save the index of a quest that is active complete or otherwise known
        @quests << i
      end
    end
    
    # Intialize the starting index.
    @index = 0
    
    # Draw the window
    refresh
  end
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    # Clear the window.
    self.contents.clear
    
    # If there are no quests draw the default information.
    if @quests.size == 0
      
      # Draw the quest name.
      self.contents.draw_text(4, 0, 300, 32, 
        Quest_Settings::QUEST_DEF_NAME)
        
      # Draw the quest description.
      self.contents.font.color = normal_color
      self.contents.draw_wrap_text(4, 64, 300, 32, 
        Quest_Settings::QUEST_DEF_DESC)

    else

      # Return before we make a mistake.
      return if @quests[index].nil?
        
      # Draw the quest name.
      self.contents.draw_text(4, 0, 300, 32, 
        Quest_Settings::QUEST_NAMES[@index])
  
      # Draw whether quest status.
      if $game_variables[@index + Quest_Settings::VARIABLE_OFFSET] == 1
        self.contents.font.color = Color.new(255,0,0,255)
        self.contents.draw_text(150, 0, 120, 32, "Active", 2)
      else
        self.contents.font.color = Color.new(0,255,0,255)
        self.contents.draw_text(150, 0, 120, 32, "Complete", 2)
      end
  
      # Draw the quest description.
      self.contents.font.color = normal_color
      self.contents.draw_wrap_text(4, 64, 300, 32, 
        Quest_Settings::QUEST_DESCS[@index])
    end
  end
end

#==============================================================================
# ** Bitmap Class Add-ons from MACL 2.1
# NOTE: If you have the MACL, don't delete this.
# Make sure this is below the MACL
#------------------------------------------------------------------------------
class Bitmap
  #--------------------------------------------------------------------------
  # * Dummy Bitmap  
  #--------------------------------------------------------------------------
  @@dummy = Bitmap.new(32, 32)
  attr_accessor :dummy
  #--------------------------------------------------------------------------
  #   Name      : Text Size
  #   Info      : Gets text size based off dummy bitmap
  #   Author    : SephirothSpawn
  #   Call Info : One Argument, a String
  #--------------------------------------------------------------------------
  def Bitmap.text_size(text)
    return @@dummy.text_size(text)
  end
  #-------------------------------------------------------------------------
  #   Name      : Draw Wrapped Text
  #   Info      : Draws Text with Text Wrap
  #   Author    : Trickster
  #   Call Info : Five Arguments
  #               Integer X and Y, Define Position
  #               Integer Width, defines the width of the text rectangle
  #               Integer Height, defines the height of the text
  #               String Text, Text to be drawn
  #   Modified  : Brew.  Add 'p' for line breaks
  #-------------------------------------------------------------------------
  def draw_wrap_text(x, y, width, height, text)
    # Get Array of Text
    strings = text.split
    # Run Through Array of Strings
    strings.each do |string|
      # Get Word
      word = string + ' '
      # If /n move to next line
      if string == " /n"
        x = 0
        y += height
        next
      end
      # Get Word Width
      word_width = text_size(word).width
      # If Can't Fit on Line move to next one
      x, y = 0, y + height if x + word_width > width
      # Draw Text Memory
      self.draw_text(x, y, word_width, height, word)
      # Add To X
      x += word_width
    end
  end
end

#==============================================================================
# * Scene_Journal
#------------------------------------------------------------------------------
#  This class contains the windows for the quest menu 
#  To access from the menu, insert $scene = Scene_Journal.new in your menu
#
#  Brewmeister - V10MAR08
#  Props to Lambchop (original creator) & Trickster (draw_wrap_text method)
#==============================================================================

class Scene_Journal
  #--------------------------------------------------------------------------
  # * Main Processing
  #--------------------------------------------------------------------------
  def main
    # Intialize the map in the background.
    @spriteset = Spriteset_Map.new
    
    # Initialize our journal window.
    @journal_window = Window_Journal.new
    @journal_window.back_opacity = 190
    # So we get that arrow that points down.
    @journal_window.pause = true
    
    # Create a sprite object to display the quest image.
    @quest_sprite = Sprite.new
    @quest_sprite.bitmap = nil
    @quest_sprite.z = 999
    
    Graphics.transition
    
    update_quest_picture(@journal_window.index)

    loop do
      Graphics.update
      Input.update
      update
      if $scene != self
        break
      end  
    end

    Graphics.freeze
    
    @journal_window.dispose
    
    # Dispose of the sprite and its bitmap
    @quest_sprite.bitmap.dispose unless @quest_sprite.bitmap.nil?
    @quest_sprite.dispose unless @quest_sprite.disposed?
    
    # Get rid of the map.
    @spriteset.dispose
  end
  #--------------------------------------------------------------------------
  # * Frame Update
  #--------------------------------------------------------------------------
  def update
    update_journal if @journal_window.active
  end
  #--------------------------------------------------------------------------
  # * Update Journal
  #--------------------------------------------------------------------------
  def update_journal
   
    # Cancel key pressed (go to menu)
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      $scene = Scene_Menu.new(4)
      return
    end
    
    # No quests. No need to check for input.
    return if @journal_window.quests.size == 0
    
    # The user has pressed the down button.
    if Input.trigger?(Input::DOWN)
      # Increment the index.
      @journal_window.index += 1
      # Test to see if we exceed the maximum if so reset the index.
      if @journal_window.index > (@journal_window.quests.size - 1)
        # Set the position to zero.
        @journal_window.index = 0
      end
      
      update_quest_picture(@journal_window.index)
      
      # Refresh the window.
      @journal_window.refresh
    end
    
    # The user has pressed the up button.
    if Input.trigger?(Input::UP)
      # Decrement the index.
      @journal_window.index -= 1
      # Test to see if we are less than zero.
      if @journal_window.index < 0
        # Set the current index to the last position in the quest log.
        @journal_window.index = @journal_window.quests.size
      end
      
      update_quest_picture(@journal_window.index)
        
      # Refresh the window.
      @journal_window.refresh
    end
  end
  #--------------------------------------------------------------------------
  # * Update Quest Picture
  #--------------------------------------------------------------------------
  def update_quest_picture(index)
    # The index of the picture.
    questpic_index = index
    # If the current index exceeds the picture to be used.
    if index > (Quest_Settings::QUEST_PICS.size - 1)
      questpic_index = 0
    end
    
    # Change the sprite's bitmap.
    @quest_sprite.bitmap = 
      RPG::Cache.picture(Quest_Settings::QUEST_PIC_DIR + 
      Quest_Settings::QUEST_PICS[questpic_index])
      
    @quest_sprite.x = 640 - @quest_sprite.bitmap.width
  end
end

Alright its about time I explained what I did. The big thing for starters is the incorporation of module Quest_Settings. That's where I put all the quest strings and descriptions etc. I tossed Window_JournalRight it is now just a simple Sprite object contained within Scene_Journal. In Window_Journal I made the window height to the screen's size, 480. And the quests that you about are decided in the initialize. So there's no longer a loop in refresh.

Good luck with it Xathia Vastar! :thumb:

[edit] I dropped the ball... again. If you came back to ask for what if no quests are there nothing is displayed. Just updated the code so that if no quests are available you will get the message that there are no active or completed quests for the user. That is corrected in the code.
 
I'm not sure if this would be an ideal place to stick the code, since the picture stays on the screen and doesn't go away even when you exit. This is taken from the Window_Journal class:

Code:
 if @quests[@index].nil?
      self.contents.draw_wrap_text(4, 64, 428, 32, "there are no quests in the journal")

          @quest_sprite = Sprite.new
        @quest_sprite.bitmap = nil
       @quest_sprite.z = 999
      
        @quest_sprite.bitmap = 
        RPG::Cache.picture('journal/' + Quest_Settings::QUEST_PICS[0])
        
      @quest_sprite.x = 640 - @quest_sprite.bitmap.width[/color]
 

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