bitmap.blt in Window

bsides

Veteran
Veteran
Joined
Feb 17, 2013
Messages
40
Reaction score
11
First Language
Portuguese
Primarily Uses
Hello all,


So I'm trying to modify the way a part of how the Window works. Right now you have the windowskin that dictates (almost) every graphic element from the interface. What I want to change first is the menu items - I want them to appear as buttons, like a web interface or something like it.


Think about Dissidia Final Fantasy menu:





You have a button background and, when you hover, it changes the color.


TL;DR: I'm modifying the Window so in a item menu, it would look like the screenshot above - a button background and a hover effect. Could you please point me if I'm going the right direction? I'm having a really hard time drawing the background buttons and the hover effect.


So I eliminated the background and frame from window, just replacing their functions with nothing:


Window.prototype._refreshBack = function() {
  this._windowBackSprite.bitmap = null;
};
Window.prototype._refreshFrame = function() {
  this._windowFrameSprite.bitmap = null;
};




Then modified Window.prototype.updateTransform to include this._updateButtonBackground(), just before this._updateContents().


Window.prototype._updateButtonBackground = function() {
  var cursorOpacity = this.contentsOpacity;
  this._windowButtonBackground.alpha = cursorOpacity / 255;
  this._windowButtonBackground.visible = this.isOpen();
};




Then in Window.prototype._refreshAllParts I included this._refreshBackgroundButton(), (before _refreshCursor()) that goes like this:


Window.prototype._refreshButtonBackground = function() {
var pad = this._padding;
var w = this._width;
var h = this._height;

var buttonImage = ImageManager.loadSystem('ButtonBackground');

var bitmap = new Bitmap(w, h);

bitmap.blt(buttonImage, 0, 0, 300, 47, x, y, w, h);
};


The thing is: it doesn't get drawn. The image simply don't show. I know the bitmap part is right, the image is there (or else ImageManager would throw an error)... if I do bitmap.fillAll('#ff0000') it shows red and in the correct place, but nothing about the image. Am I missing something here?


Thanks for any input!
 
Last edited by a moderator:

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,848
First Language
English
All images need to be drawn on a display object.


Windows and Sprites provide a bitmap property by default.


The Bitmap object associated with windows is accessed via "contents"


So if you look around Window_Base you see


Window_Base.prototype.createContents = function() {
    this.contents = new Bitmap(this.contentsWidth(), this.contentsHeight());
    this.resetFontSettings();
};




You need to blt onto an existing bitmap, or create another bitmap of your own (requires modifications to the window rendering methods), or create a sprite and then blt onto that sprite's bitmap (this is much easier).


I would recommend creating a new sprite and then adding the sprite to the window.


Each sprite would then function as a stand-alone button, which you can independently interact with (eg touch to select)
 
Last edited by a moderator:

bsides

Veteran
Veteran
Joined
Feb 17, 2013
Messages
40
Reaction score
11
First Language
Portuguese
Primarily Uses
@Tsukihime thanks for the thoughtful answer. 


In Window.prototype._createAllParts, I inserted another sprite, just like this._windowFrameSprite = new Sprite(), named this._windowButtonBackground. The rest I attempted to reprise what is done in FrameSprite or BackgroundSprite or even CursorSprite but somehow I can't get it to display. I'm used to addChild in Scenes to make the image display after bitmap.blt'ing it, but in this scenario, I'm not sure what is happening.


Would also be interesting if I don't draw an image every time the cursor is active, but just a bitmap filled with color and maybe adding an ADD effect to it. You know what I mean?


EDIT: After giving it some thought, I believe the best course of action here is to make the sprite in Window object then drawing only in Window_Selectable. This way I can control more each button by having the number of items will be drawn in the screen. Could you give me directions on that?
 
Last edited by a moderator:

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,848
First Language
English
I don't know if this will help, but here is some basic code.


We start with a simple custom sprite class of my own


function Sprite_HoverButton() {
this.initialize.apply(this, arguments);
};

Sprite_HoverButton.prototype = Object.create(Sprite.prototype);
Sprite_HoverButton.prototype.constructor = Sprite_HoverButton;

Sprite_HoverButton.prototype.initialize = function() {
Sprite.prototype.initialize.call(this);
this.drawBitmap();
};

Sprite_HoverButton.prototype.drawBitmap = function() {
this.bitmap = new Bitmap(200, 200);
this.bitmap.fillRect(0, 0, 200, 200, "rgb(255, 0, 0)");
};


Pretty simple: boilerplate code for declaring a class. When it's created, I assign a red square to it .


Now, I want to display it somewhere. Using the approach you suggested, I will add it to a window. I will put it in the party menu, so when you go to the menu, you will see a big red square.


var TH_WindowMenuStatus_refresh = Window_MenuStatus.prototype.refresh;
Window_MenuStatus.prototype.refresh = function() {
TH_WindowMenuStatus_refresh.call(this);
this._mySpr = new Sprite_HoverButton();
this.addChild(this._mySpr);
};


Go in the game, press X, and you'll see a big red square.


You can now change the square to use a picture, define your update method to check whether the mouse is hovering over it, and so on.


I would recommend starting over from scratch and trying to figure out where things went wrong.
 

bsides

Veteran
Veteran
Joined
Feb 17, 2013
Messages
40
Reaction score
11
First Language
Portuguese
Primarily Uses
This is very good, thank you again. Although it doesn't apply to what I was trying, it contains good starting point and well, theorized where things go, which I'm finding it hard to organize... I wish there were a help file / documentation about what is each object and its methods (like the one in the RPG Maker MV Help File and some elements there).


Having said that, what I was trying to achieve is:


1 - Remove frame and background windowskin;


2 - In menus, anything that is selectable/interactable (I call them menu items) should have a background image, a button image that would fit the contents of the larger item;


3 - The cursor select shouldn't use windowskin, it should only "color" the background buttom image, like an blend effect (which I'm unsure this version of pixie supports);


4 - Besides that, the cursor should be a cursor image statically put in the left, like Final Fantasy XIII or many others (a hand or an arrow);


I know there is a lot here and I'm not asking you to make it for me, but I'm just realizing it's much more work than I thought. If you can just point any flaw in my logic, would help a lot.


1 - That is in Window object, specifically in refreshBackground and refreshFrame methods;


2 - This one looks a little harder. I'm guessing I should modify Window_Selectable in drawAllItems method, but I should addChild somewhere else so it doesn't overlap the other "layers" (is that correct? I couldnt find the layer order of the things drawn). Also, the drawn button should have the same principle as the refreshCursor method in Window, as in drawing 4 corners (top left / top right / bottom left / bottom right) and 4 directions (top / bottom / left / right) to fit its contents after measuring the text with Window_Selectable itemWidth method. Ufa!


3 - I don't really know if I can achieve that since I only wish to color the image in the background and not the whole thing (the image in the background and the whole background, since the image isn't square, it's a complex shape). So maybe I should drop this idea and just draw the button highlighted - but then I need to check the item's width which is only in Window_Selectable and not in Window's refreshCursor... that's kind of confusing. How could I do that?


4 - Well that's in Window object, refreshCursor method. Like #1, that's easy to change.


Sorry if this is way too bigger than the original message, but since you were so helpful, maybe I could get more thoughts :)


(and thanks again!)
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,848
First Language
English
Personally, I would move away from the Window approach and just build the menu using sprites.


Have a sprite as your container, and then add sprites to it for your buttons, titles, and so on.


Then create another sprite as the cursor and implement logic for navigating between buttons.
 

bsides

Veteran
Veteran
Joined
Feb 17, 2013
Messages
40
Reaction score
11
First Language
Portuguese
Primarily Uses
Yes, I followed your suggestion. After banging my head in the wall for a while I discovered that the bitmap may not be ready when you call it to BLT, which I found very weird and unsolutionable. In fact there is a fix, I ended up preloading it with TDDP plugin (TDDP_Preloader). Now I can load the bitmap and use anytime I want, even blt'ing wherever. But really, what is the deal here? Anyway.


I created a method called drawButton in Window_Selectable and applied it just before drawItem() is called into the method drawAllItems. The thing is, I had to addChildToBack because if I just addChild it goes above the text contents. That would be fine whatsoever if I hadn't encontered more problems unfortunatelly:


1 - I need a way to find those sprites I addChildToBack'ed because there are some menus that just rebuild the whole thing and if the sprites are added in this window, when you refresh via other windoes, it doesn't "dispose" of these childs, making it draw all over again. I just noticed this because I have transparency in the button and it goes darker and darker. The menu I'm testing is the skill menu that calls SkillList over and over if you have more than one type of skill and select others and go back. This is such a memory hog too... why redraw everything over and over? I tried using removeChildAt but I don't know how many buttonSprites I drew before!!! Even making a "for loop" for every child inside the window, I couldn't remove them all without a solid reference. This is such a pain.


2 - I have a white button background image and a darker button cursor. Now I have to make the text lighter for when I hover the cursor - and here lies all the trouble in the world. Since windowCursorSprite (in Window, refreshCursor method) only holds the image, it knows nothing about its text contents. So even if I try to do this.contentx.textColor = something else there, it won't change a thing because it doesn't draw any text... another pain. What I'm trying to check is if there's anyway that I can redraw that content if the cursor is active in it, while in refresh method of Window_Selectable... is there such method? I couldn't find it.


These are my main headaches right now. Oh and the bitmap loader... that is a little weird.


Thanks again for all the help @Tsukihime!
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,848
First Language
English
@bsides


The reason why bitmaps may not be ready when you need it is due to the asynchronous nature of loading an image.


Rather than just having the game freeze up while it's loading a a resource that may be large (like it does in previous engines), it will instead load it in parallel (or something. I'm not too clear how it works)


There are two general solutions


1. Preload them, as you have discovered. If you don't want to deal with any of that async headaches, just have the game prepare all of the assets that will be required beforehand. This is common practice and generally more user-friendly if the alternative was to make them wait a long time in the middle of the game, especially if it requires an internet connection.


2. Execute event handlers. You can add a "load" listener to the bitmap, which is basically just a function. When the bitmap is loaded, it will fire off any "on loaded" functions that have been assigned to it. This means, however, that there may be delays before the entire menu shows up. And parts of the menu could even show up at different times depending on when the images are loaded. Preloading would look more smooth here.


Regarding display order, sprites are rendered from bottom to top as you have found.


The window's contents sprite is also just another sprite, so depending on whether you add it before or after it, the image will appear in different places.


The general solution is to hold references to the sprites.


this._titleSprite = new Sprite();
this.addChild(this._titleSprite);

var button = new Sprite();
this._menuButtons.push(button);
this.addChild(button)


Now you have solid references. This is the approach used in MV.


For the cursor, why not just create your own sprite?
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

Day 9 of giveaways! 8 prizes today :D
He mad, but he cute :kaopride:

Our latest feature is an interview with... me?!

People4_2 (Capelet off and on) added!

Just beat the last of us 2 last night and starting jedi: fallen order right now, both use unreal engine & when I say i knew 80% of jedi's buttons right away because they were the same buttons as TLOU2 its ridiculous, even the same narrow hallway crawl and barely-made-it jump they do. Unreal Engine is just big budget RPG Maker the way they make games nearly identical at its core lol.

Forum statistics

Threads
106,040
Messages
1,018,470
Members
137,821
Latest member
Capterson
Top