Trouble with adding a button.

Kilitar

Veteran
Veteran
Joined
Jul 28, 2015
Messages
141
Reaction score
41
First Language
czech
Primarily Uses
RMMV
Hello, I have no troubles to adding/rearrange/resize buttons in Window_MenuCommand objects. It is simple plugin using methods already available as part of it.
My app is made for android tablets/phones and it has included pedometter and GPS plugin as it interacts with real world around. Because it is for mobiles, I re-aranged game menu to look like this.
Menu.png


My problem is, I did not found way to add single button on window/scene without buttons included. Leaving screen on mobilw Like status scene - which looks like
status.png


I am bit lost between all those handlers, childs (or maybe grandfathers). Tried few written and youtube tutorials but still no luck.

Thank you for any advice.
 

Poryg

Dark Lord of the Castle of Javascreeps
Veteran
Joined
Mar 23, 2017
Messages
4,048
Reaction score
10,278
First Language
Czech
Primarily Uses
RMMV
I'd recommend you to create a transparent Window_Command prototype window.
As for commands, it's easy with them. You need a command, added via window.addCommand(commandName, commandText) and a command's handler:
window.setHandler (commandName, callback function)
Command is the visual part of a command, handler is the functional part of the command and says what happens when you press it.
For example in this case it would be like this:
window.addCommand("backButton", "Back");
window.setHandler("backButton", SceneManager.popScene());
 

Aloe Guvner

Walrus
Veteran
Joined
Sep 28, 2017
Messages
1,627
Reaction score
1,066
First Language
English
Primarily Uses
RMMV
Another method is to create a Sprite of the button, and then add a check in the update loop of the scene for if the button was pressed by TouchInput. I did this in my Mobile Game UI plugin (link in signature), you can study that to see how it was done.

However, I do believe Poryg's idea is simpler, and it would be better to try that first.
 

Kilitar

Veteran
Veteran
Joined
Jul 28, 2015
Messages
141
Reaction score
41
First Language
czech
Primarily Uses
RMMV
Thank you,

Tried and made some progress.
I made own prototype of BackButtonWindow

Code:
function BackButtonWindow() {
    this.initialize.apply(this, arguments);   
};

BackButtonWindow.prototype = Object.create(Window_Command.prototype);
BackButtonWindow.prototype.constructor = BackButtonWindow;


BackButtonWindow.prototype.initialize = function(x,y) {
  Window_Command.prototype.initialize.call(this, x, y);
  var width = 240;
  var height = 126;
  Window_Selectable.prototype.initialize.call(this, x, y, width, height);
   this.addCommand("backButton", "Back");
  this.setHandler("backButton", SceneManager.popScene());
};

BackButtonWindow.prototype.update = function() {
  Window_Command.prototype.update.call(this);
};
And I call it from Scene_Status as new child
Code:
Scene_Status.prototype.create = function() {
    Scene_MenuBase.prototype.create.call(this);
    this._statusWindow = new Window_Status();
    this._statusWindow.setHandler('cancel',   this.popScene.bind(this));
    this._statusWindow.setHandler('pagedown', this.nextActor.bind(this));
    this._statusWindow.setHandler('pageup',   this.previousActor.bind(this));
    this._statusWindow.reserveFaceImages();
    this.addWindow(this._statusWindow); 
    var backButton = new BackButtonWindow(this.width - 240, this.height - 126);
    this.addChild(backButton);
};
I got error SceneManager.popScene is not a function
without //this.setHandler("backButton", SceneManager.popScene()); it works partially - small empty window is displayed at bottom right corner, but with no text on it.
 

Poryg

Dark Lord of the Castle of Javascreeps
Veteran
Joined
Mar 23, 2017
Messages
4,048
Reaction score
10,278
First Language
Czech
Primarily Uses
RMMV
My bad. I thought it was like this and it is the other way around. The first parameter in addCommand function is command text, the second parameter is command name. So you just need to switch the two parameters inside the addCommand function.
Also, it is much better to rename the variable from backButton to at least this._backButton (in which caswe don't reference it as var), because you may need to reference it sometime and will not be if you keep it as a normal local variable.
And for windows we don't use addChild, but addWindow. addChild works too, but addWindow adds the window to window layer.

As for SceneManager.popScene, it is a function. If it doesn't work, you can just use SceneManager.pop() and it will work the same. If neither of these work, then that means it will work without brackets, meaning not SceneManager.popScene(), but SceneManager.popScene
 
Last edited:

Kilitar

Veteran
Veteran
Joined
Jul 28, 2015
Messages
141
Reaction score
41
First Language
czech
Primarily Uses
RMMV
Well, replaced as you advised, but still no luck. AT least this.setHandler('backButton', SceneManager.pop()); does not return error.
Window is created but no button visible on it. No text.

Now I have it placed inside BackButtonWindow.prototype.initialize

If I move addCommand and setHandler lines both into update function instead of initialiye, status scene is closed immediatelly after opened - so it works somehow, but not as part of button which is not visible.
 

Poryg

Dark Lord of the Castle of Javascreeps
Veteran
Joined
Mar 23, 2017
Messages
4,048
Reaction score
10,278
First Language
Czech
Primarily Uses
RMMV
Ah... I see where the problems are. At least one of them :D
I forgot you need to bind the function to the handler.
Code:
function BackButtonWindow() {
   this.initialize.apply(this, arguments);  
};

BackButtonWindow.prototype = Object.create(Window_Command.prototype);
BackButtonWindow.prototype.constructor = BackButtonWindow;


BackButtonWindow.prototype.initialize = function(x,y) {
  Window_Command.prototype.initialize.call(this, x, y);
   this.addCommand("Back", "backButton");
  this.setHandler("backButton", SceneManager.popScene.bind(this));
};

BackButtonWindow.prototype.windowWidth = function () {
return 240;
};

BackButtonWindow.prototype.windowHeight = function () {
return this.fittingHeight(1);
}
I have also reworked your code, because I noticed you called Window_Command and after setting width you called Window_Selectable, effectively overwriting some settings from Window_Command. It is also completely unnecessary to set height by a fixed number, since Window_Command autoresizes itself to maximum of your commands if height is higher. And if you are going to create an update function only to call Window_Command prototype's update, it's unnecessary to create it, because the child automatically inherits all methods from its parent.
Hopefully it works now.
 

Kilitar

Veteran
Veteran
Joined
Jul 28, 2015
Messages
141
Reaction score
41
First Language
czech
Primarily Uses
RMMV
Still no luck.
error "cannot read property 'bind' of undefined
This button is a very resistant beast :]
 

Aloe Guvner

Walrus
Veteran
Joined
Sep 28, 2017
Messages
1,627
Reaction score
1,066
First Language
English
Primarily Uses
RMMV
Commands are added in the window, but handlers are set in the scene. The above code is trying to do both within the window initialize function.
 

Poryg

Dark Lord of the Castle of Javascreeps
Veteran
Joined
Mar 23, 2017
Messages
4,048
Reaction score
10,278
First Language
Czech
Primarily Uses
RMMV
There's no difference between setting handlers from window and from Scene, because both names address the same thing. The reason it is done via Scene is due to allocation in memory. Javascript handles memory allocation asynchronously, meaning that if you create an object after you try to assign something to its property, it will crash. Faster computers have no problems with this. Slower ones do though, so the engine is built like this to prevent crashes. However, I've already built a plugin where I assigned a handler from window. There I solved it by pushing 3 functions between handler and commands to make sure there's enough time for the window to be properly created.
However, the problem was completely somewhere else. I tried to call popScene, but it's not a method of SceneManager... But of the scene itself. Meaning if called from window, it should have been SceneManager._scene.popScene.bind(this).
Anyway, this is the fixed thing.

Code:
function BackButtonWindow() {
   this.initialize.apply(this, arguments);
};

BackButtonWindow.prototype = Object.create(Window_Command.prototype);
BackButtonWindow.prototype.constructor = BackButtonWindow;

BackButtonWindow.prototype.windowWidth = function () {
return 240;
};

BackButtonWindow.prototype.windowHeight = function () {
return this.fittingHeight(1);
}

BackButtonWindow.prototype.makeCommandList = function() {
this.addCommand("Back", "backButton");
}

Scene_Status.prototype.create = function() {
   Scene_MenuBase.prototype.create.call(this);
   this._statusWindow = new Window_Status();
   this._statusWindow.setHandler('cancel',   this.popScene.bind(this));
   this._statusWindow.setHandler('pagedown', this.nextActor.bind(this));
   this._statusWindow.setHandler('pageup',   this.previousActor.bind(this));
   this._statusWindow.reserveFaceImages();
   this.addWindow(this._statusWindow);
   this._backButton = new BackButtonWindow(this.width - 240, this.height - 126);
   this._backButton.setHandler('backButton', this.popScene.bind(this));
   this.addWindow(this._backButton);
};
 

Kilitar

Veteran
Veteran
Joined
Jul 28, 2015
Messages
141
Reaction score
41
First Language
czech
Primarily Uses
RMMV
Thx it worked for one problem - button now works - but still has no text on it.
 

Poryg

Dark Lord of the Castle of Javascreeps
Veteran
Joined
Mar 23, 2017
Messages
4,048
Reaction score
10,278
First Language
Czech
Primarily Uses
RMMV
I suspect a compatibility issue, because on a vanilla project it works 100%. Which plugins does your project use? If you deactivate custom fonts plugins, does the issue still stand? (I can only guess here, but I'd say it has to do with a plugin that influences texts).
 

Aloe Guvner

Walrus
Veteran
Joined
Sep 28, 2017
Messages
1,627
Reaction score
1,066
First Language
English
Primarily Uses
RMMV
My comment wasn't about memory, but context.
BackButtonWindow.prototype.initialize = function(x,y) { Window_Command.prototype.initialize.call(this, x, y); this.addCommand("Back", "backButton"); this.setHandler("backButton", SceneManager.popScene.bind(this)); };
I should have expanded to say the setHandler method is called in the context of the scene so that it can bind the correct 'this' value to the handler function. But it's a useless comment now because you already fixed that part.
 

Kilitar

Veteran
Veteran
Joined
Jul 28, 2015
Messages
141
Reaction score
41
First Language
czech
Primarily Uses
RMMV
Yep, Poryg - your script works now,
I missed part "BackButtonWindow.prototype.makeCommandList = function()"

Great job from both of you guys and thank for your time.
I also understand much better now how windows are handled within scene Now I am going extend this concept to scroll between actors via buttons as well so fingers crossed :).
 

Poryg

Dark Lord of the Castle of Javascreeps
Veteran
Joined
Mar 23, 2017
Messages
4,048
Reaction score
10,278
First Language
Czech
Primarily Uses
RMMV
@Kilitar Default Scene_Status has this already done, just to pageup and pagedown, so you can inspire yourself there :)
@Aloe Guvner True, context is important. And consistency too :D
 

Kilitar

Veteran
Veteran
Joined
Jul 28, 2015
Messages
141
Reaction score
41
First Language
czech
Primarily Uses
RMMV
@Poryg @Aloe Guvner - I would like another your advice with scroll between actors via buttons.

I used same concept which worked for BackButton. Add button and set correct handler for it.
Issue I have now: next - previous button works only once and switch to next actor. Then it takes focus and cannot be clicked anymore (neither any other button). But keyboard works no matter my button menu is stuck. (esc to leave and page up/down for scrolls).

Tried few hours, but no luck Thank you.

Code:
Scene_Status.prototype.create = function() {
   Scene_MenuBase.prototype.create.call(this);
   this._statusWindow = new Window_Status();
   this._statusWindow.setHandler('cancel',   this.popScene.bind(this));
   this._statusWindow.setHandler('pagedown', this.nextActor.bind(this));
   this._statusWindow.setHandler('pageup',   this.previousActor.bind(this));
   this._statusWindow.reserveFaceImages();
   this.addWindow(this._statusWindow);
   this._nextActButton = new PreviousNextActorButtonWindow(this.width/2 - 420/2, this.height - 132);
   this._nextActButton.setHandler('nextActorButton', this.nextActor.bind(this));
   this._nextActButton.setHandler('previousActorButton',   this.previousActor.bind(this));
   this._nextActButton.setHandler('backButton', this.popScene.bind(this));   
   this.addChild(this._nextActButton);
};



//-----------------------------------------------------------------------------
//
//  PreviousNextActor button
//
//-----------------------------------------------------------------------------

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

PreviousNextActorButtonWindow.prototype = Object.create(Window_Command.prototype);
PreviousNextActorButtonWindow.prototype.constructor = PreviousNextActorButtonWindow;


PreviousNextActorButtonWindow.prototype.initialize = function(x,y) {
  Window_Command.prototype.initialize.call(this, x, y);
};


PreviousNextActorButtonWindow.prototype.makeCommandList = function() {
this.addCommand("<<<", 'previousActorButton');
this.addCommand("Zpět", 'backButton');
this.addCommand(">>>", 'nextActorButton');
};

PreviousNextActorButtonWindow.prototype.windowWidth = function () {
return 420;
};

PreviousNextActorButtonWindow.prototype.windowHeight = function () {
return this.fittingHeight(1);
};

PreviousNextActorButtonWindow.prototype.lineHeight = function() {
return 32 * 3;
};
PreviousNextActorButtonWindow.prototype.itemTextAlign = function() {
return 'center';
};

PreviousNextActorButtonWindow.prototype.standardBackOpacity = function() {
    return 255;
};

PreviousNextActorButtonWindow.prototype.numVisibleRows = function() {
    return 1;
};

PreviousNextActorButtonWindow.prototype.maxCols = function() {
    return 3;
};
 

Poryg

Dark Lord of the Castle of Javascreeps
Veteran
Joined
Mar 23, 2017
Messages
4,048
Reaction score
10,278
First Language
Czech
Primarily Uses
RMMV
You need to redefine the nextActor and previousActor functions so that it ends the line with
this._backButton.activate();
Because these two functions set focus to a different window.
 

Kilitar

Veteran
Veteran
Joined
Jul 28, 2015
Messages
141
Reaction score
41
First Language
czech
Primarily Uses
RMMV
Thank you @Poryg.
I also did not found how can I check which actor is active and dynamically enable buttons based on his stats/params etc...

I can check for example this._actor._talentPoints from status scene functions.

But this._actor._talentPoints is unidentified for backbutton menu. (in fact whole actor object does not exist for "window" only for scene. How to pass active actor object properties to windows so it "knows" about it?

Goal is to have button enabled/disabled based on recent value of added property to actor object (and dynamically change enabled/disabled during scene refresh as actor spent talent points during training.


Code:
PreviousNextActorButtonWindow.prototype.makeCommandList = function() {
  if (this._actor._TalentPoints  > 0){
     this.addCommand("Talent", 'talentTrainButton', true); 
  } else {
  this.addCommand("Talent", 'talentTrainButton', false); 
 }
this.addCommand("<<<", 'previousActorButton');
this.addCommand("Zpět", 'backButton');
this.addCommand(">>>", 'nextActorButton');
this.addCommand("Popis", 'descWindowButton');
};
I feel sorry I cant do it alone and bother you so much. I found functions like setActor on other types od windows_selectable - but all have actor as parametter to be pased from "somewhere".
The way around I found is to have more "menu" clones and control them directly from scene - and add one which fits conditions,
but If I would have even more such "dynamically enabled/disabled buttons" I would need to have all combinations which might happen and it is definitelly not good approach to solve this issue.

EDIT> Sorry, I need break, it is simple and I did it multiple times before already. WIndows object works like any other "class". so i can pass actor as argument from create scene function
 
Last edited:

Poryg

Dark Lord of the Castle of Javascreeps
Veteran
Joined
Mar 23, 2017
Messages
4,048
Reaction score
10,278
First Language
Czech
Primarily Uses
RMMV
In the worst case you could do it by proper references.
SceneManager._scene is the scene. And this scene has a couple of windows, one of them contains the current actor.
So you could do inside the button's function this code:
Code:
if ($gameParty.battleMembers()[3] !== SceneManager._scene._statusWindow.actor())) this.addCommand(">>>", "nextActorButton");
if (this._commands != 3) this.select(0);
It looks awful, but is entirely possible :D
 

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

Latest Threads

Latest Posts

Latest Profile Posts


The main character of the book)
Things you can say about your rpg maker project but not your bf/gf: I'm not super committed but it's fun to play around with it.
putting a puzzle in my game that BSODs the player's computer if they complete it
I finally got a book out the door after seven years of nothing \^-^/ Now if I can get a game out the door too, that'd be great...

Forum statistics

Threads
94,366
Messages
920,300
Members
124,131
Latest member
Tharene
Top