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.

Display Variable in HUD Window?

Hey, all!

I'm trying to teach myself a bit of RGSS. Keep in mind that I literally know nothing about it other than what I state in this post.

Basically, I'm trying to have a window that stays on the screen (not the menu), an HUD of sorts, that displays a variable set in game. I've tried to read/analyze various topics (making use of the ancient art of Search-jitsu), and here's what I've come up with:

This is a new script inserted above Main:

Code:
class Window_hunger < Window_Base
 def initialize
   super(170, 400, 200, 80)
      self.back_opacity = 145
  self.contents = Bitmap.new(200 - 32, 80 - 32)
   refresh
  end
def refresh
      self.contents.clear
$game_variables[25] = @hunger
        self.contents.draw_text(0, 0, 190, 70, $game_variables[25].to_s)
    end
end

This I added onto the end of Scene_Map:

Code:
#HUD2 UPDATE
class Scene_Map
  alias hunger_main main
  alias hunger_update update
  def main
    @hunger = Window_hunger.new
    hunger_main
    @hunger.dispose
  end
  def update
    @hunger.update
    hunger_update
  end
end 

It sure enough displays a window, and it displays a "0" where a zero should be. However, I'm not sure...

1. Is the 0 there actually referring to the fact that the game starts with the variable as 0, or did I do that wrong?
2. How do I make it so that it updates to stay current with whatever in this case Variable 25 is?

I can't really answer any questions about why I did what I did; this is the result of about 3 hours of playing around typing things and trying to make it work based off in-game scripts and what a few other people have done. I'd appreciate all help; thanks!
 
Code:
$game_variables[25] = @hunger

With this line you set variable 25 to the value of @hunger that is 0 since you have never initialized it. If your purpose is to show the value of that variable, without changing it, remove this line.
However you have to call your refresh method if you want the content updated, and you only call update, that, besides, is that of Window_Base and does nothing about the contents you want to show.
You need an update method too, that could check if the value is changed and call refresh if so.
 
Yep, the "0" is displaying the 'current' value of Variable 25 when the window gets created.

Get rid of

$game_variables[25] = @hunger

This will just keep resetting Variable 25 to 'nil' or '0'

As it is, your window updates if you leave the scene & come back (go to the menu)

Your calling @hunger.update from Scene_Map, but you haven't defined 'update' in Window_Hunger.
You defined 'refresh' in Window_Hunger, but it's not getting called until you recreate the window.

I think, since you're calling hunger_update (the aliased method), you can simply add

Code:
def update
   refresh
end

to your Window_hunger class

give it a try

Be Well

[ EDIT ]

After pondering Charlie's post, it's probably safer, and more efficient to use a comparison.
that way, you're only refreshing the window when necessary.

Here's my Window_Hunger script in it's entirety. (I included the Scene_Map overload in the same script for portability / ease of implementation)

Code:
class Window_hunger < Window_Base
  def initialize
    super(170, 400, 200, 80)
      self.back_opacity = 145
    self.contents = Bitmap.new(200 - 32, 80 - 32)
    refresh
  end
  def refresh
    self.contents.clear
    @hunger = $game_variables[25]
    self.contents.draw_text(0, 0, 190, 70, $game_variables[25].to_s)
  end
  def update
    super
    if $game_variables[25] != @hunger
       refresh
    end
  end
end
  
#HUD2 UPDATE
class Scene_Map
  alias hunger_main main
  alias hunger_update update
  def main
    @hunger = Window_hunger.new
    hunger_main
    @hunger.dispose
  end
  def update
    @hunger.update
    hunger_update
  end
end 

Be Well
 
Charlie.lee and especially Brewmeister, thanks so much! I appreciate it, and I think I understand the process a bit better!

I'm going to have to sit here and thing about it for awhile-- I don't quite understand alias and how "def update"/"def refresh" work, but I'll mess with it and see what happens. Thanks again!

EDIT-- After playing with it some more, here's what I ended up with:

Code:
class Window_hunger < Window_Base
  def initialize
    super(170, 400, 170, 80)
      self.back_opacity = 145
    self.contents = Bitmap.new(170 - 32, 80 - 32)
    refresh
  end
  def refresh
    self.contents.clear
    @hunger = $game_variables[25]
     self.contents.font.color = normal_color
    self.contents.draw_text(0, 0, 120, 32, "Energy:")
    self.contents.font.color = normal_color
    self.contents.draw_text(0, 0, 90, 32, $game_variables[25].to_s, 2)
      end
  def update
    super
    if $game_variables[25] != @hunger
       refresh
    end
  end
end

Got that after looking at the scripts for gold and steps in the menu. Woot, woot-- proud of my first scripting efforts!
 
 
Looks good.

You're quite welcome.

Here's the way I understand alias.

It allows you to extend a method, the same way that overloading allows you to extend a class.

The definition in the docs is a bit misleading, until you understand it

alias newmethod oldmethod

So, you're creating a Symbol (newmethod) that points at the code in the original method.

Then, you create your own version of the method, and call the 'old' code using the symbol.
<pre>
def oldmethod  # redefine the oldmethod to include your own code
  my new code
  newmethod  # call the original code from the old method
end<pre>

Does that help?

Be Well
 
Brewmeister, I appreciate it; unfortunately, as I said-- I've only had a few hours with RGSS (I figured that, after 3-4 years with RMXP, it's time to learn), and all of my knowledge is practical, so unfortunately talk such as class, method, and overloading really doesn't mean anything to me. However, I do seem to understand the concept of calling the old code and all of that stuff-- as I learn more, I'll come back to your answer and it'll probably make even more sense.

Thanks again! Have a great day.
 

khmp

Sponsor

Gratz on making the HUD King Moogle. Just a few FYI's from me to help you out with your RGSS.

In the initialize method of Window_Hunger you don't need to say:
Code:
self.contents = bitmap.new(170 - 32, 80 - 32)
You can just use:
Code:
self.contents = bitmap.new(width - 32, height - 32)
This way you don't have to remember to change both the window's size and the bitmap's size. Not that the lines are very far apart, but it could lead to some odd bugs that might take you a while to track down if you miss one or the other.

In update you clear the whole bitmap that you are drawing to. This is inefficient in most cases. Not so sure in your case because your window is almost the same size as your text. But anyway its better to define a Rect object to clear out the portion you are drawing to rather than clearing out the whole window. It bloats up the code a little bit and only compounds with more items that need to be drawn but because we are dealing with a software rendering application, graphics related operations are time consuming. Let's get back on task, first we need to create that rectangle. I'm using the size of that larger drawing surface.
Code:
clear_rect = Rect.new(0, 0, 120, 32)
Then we clear out the area by drawing a transparent rectangle in the area defined above:
Code:
self.contents.fill_rect(clear_rect, Color.new(0,0,0,0))
Also I see you are setting the font color twice. Consider the changing of the font color/size/face like a state machine. It won't change until it's told to. It doesn't see the change in color and apply it only to the next line thats drawn. And since you are setting it to the normal or default color you don't need that line of code unless the color was set to something else previously.

That brings the update code to look something like this:
Code:
def update
  @hunger = $game_variables[25]
  clear_rect = Rect.new(0,0,120,32)
  clear_color = Color.new(0,0,0,0)
  self.contents.fill_rect(clear_rect,clear_color)
  self.contents.draw_text(0,0,120,32, 'Energy:')
  self.contents.draw_text(0,0,120,32, $game_variables[25].to_s, 2)
end

Hope that helps you out even if its a little! :thumb:
 
khmp, thanks for the fabulous help; wow! Definitely makes a lot of sense, particularly with the whole updating thing. Here's the catch... I've already been moving along with the HUD. Here's where it stands now:

Code:
class Window_YourHUD < Window_Base
  def initialize
    super(0, 0, 170, 130)
       self.back_opacity = 85
    self.contents = Bitmap.new(width - 32, height  - 32)
    refresh
  end
  def refresh
    self.contents.clear
    reset_variables
    return if !@actor
    draw_actor_hp(@actor, 0, 0)
    draw_actor_sp(@actor, 0, 20)
    #
    @hunger = $game_variables[25]
    self.contents.draw_text(0, 17, 80, 80, "Energy:")
    self.contents.font.color = normal_color
    self.contents.draw_text(30, 17, 80, 80, $game_variables[25].to_s, 2)
    #
    self.contents.draw_text(0, 38, 80, 80, "Risk:")
    self.contents.font.color = normal_color
    self.contents.draw_text(30, 38, 80, 80, $game_variables[28].to_s, 2)
    
    #
    end
  def reset_variables
   @actor = $game_party.actors[0]
   @old_hp = @actor ? @actor.hp : 0
   @old_maxhp = @actor ? @actor.maxhp : 0
   @old_sp = @actor ? @actor.sp : 0
   @old_maxsp = @actor ? @actor.maxsp : 0
  end
  def update
    super
    refresh if (@actor = $game_party.actors[0] or
                @old_hp = @actor ? @actor.hp : 0 or
                @old_maxhp = @actor ? @actor.maxhp : 0 or
                @old_sp = @actor ? @actor.sp : 0 or
                @old_maxsp = @actor ? @actor.maxsp : 0)
  end
end

Now it display's the player's HP, MP, and two variables called Energy and Risk. However, the update field has significantly changed... is this new version as inefficient as the previous code with regard to updating? If so, I'm really not sure how to apply the whole rectangle thing to it... any help would be appreciated.

However, I have incorporated the width and height placeholders in the script; that'll definitely save time and preemptively solve some problems.

Thanks, everyone, for encouraging me and helping me learn this stuff. It's too bad my computer science class here at college was full, or I would have jumped right in. Ah, well, there's always next semester. ;-)
 

khmp

Sponsor

Making use of ternary operations, good work. But you're are still clearing the whole bitmap out. And you are still setting the font_color to the default text color multiple times. It's unnecessary. The refresh statement though is a little muddled. Assignments that are placed in a conditional are interpreted as true.

Code:
a = 0
if a = 1 # true

Code:
a = 0
if a == 1 # false

So when you assign the window class's actor in the conditional statement, it becomes true and it executes refresh. So only make comparisons there and no assignments.
Code:
refresh if (@old_hp != @actor.hp or
            @old_maxhp != @actor.maxhp or
            @old_sp != @actor.sp or
            @old_maxsp != @actor.maxsp)

You also might want to include a check to see if the party leader has changed.
Code:
@old_actor != $game_party.actors[0]
Because it seems you were thinking about the @actor changing, but I wasn't a 100% percent sure on whether you wanted to or not.

Good luck with it King Moogle! :thumb:
 
Thanks again. This is getting heady really quick... so, here's what I've got:

Code:
class Window_YourHUD < Window_Base
  def initialize
    super(0, 0, 170, 130)
       self.back_opacity = 85
    self.contents = Bitmap.new(width - 32, height  - 32)
    refresh
  end
  def refresh
clear_rect = Rect.new(0, 0, 170, 130)
self.contents.fill_rect(clear_rect, Color.new(0,0,0,0))
    reset_variables
    return if !@actor
    draw_actor_hp(@actor, 0, 0)
    draw_actor_sp(@actor, 0, 20)
    @hunger = $game_variables[25]
    self.contents.draw_text(0, 17, 80, 80, "Energy:")
    self.contents.draw_text(30, 17, 80, 80, $game_variables[25].to_s, 2)
    self.contents.draw_text(0, 38, 80, 80, "Risk:")
    self.contents.draw_text(30, 38, 80, 80, $game_variables[28].to_s, 2)
    end
  def reset_variables
   @actor = $game_party.actors[0]
   @old_hp = @actor ? @actor.hp : 0
   @old_maxhp = @actor ? @actor.maxhp : 0
   @old_sp = @actor ? @actor.sp : 0
   @old_maxsp = @actor ? @actor.maxsp : 0
  end
  def update
    refresh if (@old_hp = @actor ? @actor.hp : 0 or
                @old_maxhp = @actor ? @actor.maxhp : 0 or
                @old_sp = @actor ? @actor.sp : 0 or
                @old_maxsp = @actor ? @actor.maxsp : 0)
  end
end

Does that look right? Did I miss something you said, or do something wrong? I think that I've just about hit the point where I need to sit down and read through the help file (which thankfully is fairly well and clearly written).

*Hands you a cookie*

EDIT-- khmp, I just noticed the link in your signature. Rest assured that I'll be reading that for a few days; thanks!
 

khmp

Sponsor

The def update method. And the clear rect situation I think you misunderstood so I'll start with the update thing.

You are still doing assignments within a conditional. Even if the assignment occurs because of a ternary statement doesn't make it any less than an assignment. Remember the above thing I did about testing a variable as opposed to assigning a variable. To put it bluntly your update method should look like this:

Code:
  def update
    refresh if (@old_hp != @actor.hp or
            @old_maxhp != @actor.maxhp or
            @old_sp != @actor.sp or
            @old_maxsp != @actor.maxsp)
  end

Now for the clear rectangle situation. We save time drawing by not clearing the entire bitmap. You just used another method to clear the whole thing. Instead you want to clear only portions of the drawing surface, specifically only portions that need to be redrawn. The dirty region. Analogy time:

Let's say I have a huge canvas and I've been painting for months but I screw up in the upper right corner. I shouldn't have to start over with a blank canvas when the only problem exists in that corner. So instead I clean up that corner and redo that one part. Does that make more sense?

I just realized my point is moot though. You check if its necessary to refresh based on every item that appears in the window. You don't individually run through each item checking to see if it needs to updated. So my apology for confusing you on that topic. That above knowledge is still poignant for future circumstances so don't let the idea slip. I guess you can change that fill_rect call back to self.contents.clear :D
 
Alrighty, khmp... thanks again for your help and for your explanations. I think I get it a little bit clearer now.

Plus, that link in your signature is really helping. Too bad it's finals week; when I get home, I'll have to read the whole thing and play around with 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