Ethernite

Game Designer
Member
Joined
Nov 2, 2022
Messages
9
Reaction score
5
First Language
ID / EN
Primarily Uses
RMMZ
To be more specific, I want to learn how to overwrite Bitmap.drawTextEx method align to center by default.
I prefer the direct answer, so for context:

The method drawTextEx is used for the show text messages. Unlike the regular drawText, it can read escape code from control characters. But with the way drawTextEx works, it seems to me it's not that simple to change the text alignment. There are plugins that can do that, but it's hard to learn from those.

Thanks ~
 

Mac15001900

JavaScript wild sorcerer
Regular
Joined
Aug 7, 2022
Messages
392
Reaction score
524
First Language
English
Primarily Uses
RMMV
Part of the reason why it might be hard to figure it out from the plugins is that there's no simple way to do this. That method simply draws characters one after the other, not knowing in advance whether some of them will be larger, smaller, or removed because they're part of a text code. There's no built-in way to find the width of a textEx, so no way to know from where to start drawing it in order for it to be centered. There is textWidth, which will measure how long a piece of text will be using current formatting, but it ignores all the special effects (e.g "\c[1]Hi" will be treated as 7 characters).

If you don't mind losing the ability to use larger or smaller characters, you could remove all text codes and measure the width of that, and then use that to find the position to start drawing from. If you do want to support different-sized characters, it will be more complex.

I don't know exactly how those plugins do that, but it definitely might be worth looking at them some more ;)
 

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
5,258
Reaction score
4,732
First Language
EN
Primarily Uses
RMMZ
Note that MZ's drawTextEx method is defined on Window_Base, not Bitmap.

MZ has a built-in text-ex measurer, also defined on Window_Base. So, in an appropriate method, you can do something like this (assuming inputs text and areaWidth):
JavaScript:
const textWidth = this.textSizeEx(text).width;
this.drawTextEx(text, x + Math.floor((areaWidth - textWidth) / 2), y);
In case it helps, I've implemented this kind of thing in my WIP plugin Cae_Tweaks (feature Q09), which redirects all drawText to drawTextEx, complete with alignment. :kaohi:

Edit: oh I just realised I've been missing the important thing all this time...you wanted it for Show Text, not drawTextEx. See my follow-up post. :kaoslp:
 
Last edited:

Mac15001900

JavaScript wild sorcerer
Regular
Joined
Aug 7, 2022
Messages
392
Reaction score
524
First Language
English
Primarily Uses
RMMV
MZ has a built-in text-ex measurer, also defined on Window_Base
Ah, looks one of those fabled differences between MV and MZ. My bad, looks like there actually is a simple way to do this. I'll definitely need to take a look at how that function works :p
 

Ethernite

Game Designer
Member
Joined
Nov 2, 2022
Messages
9
Reaction score
5
First Language
ID / EN
Primarily Uses
RMMZ
MZ has a built-in text-ex measurer, also defined on Window_Base. So, in an appropriate method, you can do something like this (assuming inputs text and areaWidth):
JavaScript:
const textWidth = this.textSizeEx(text).width;
this.drawTextEx(text, x + Math.floor((areaWidth - textWidth) / 2), y);
In case it helps, I've implemented this kind of thing in my WIP plugin Cae_Tweaks (feature Q09), which redirects all drawText to drawTextEx, complete with alignment. :kaohi:

I do notice there's textSizeEx, but struggle to figure out where I should put them...
May I take a look at what you're referring to?
 

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
5,258
Reaction score
4,732
First Language
EN
Primarily Uses
RMMZ
OK, to centre all drawTextEx, try this:
JavaScript:
/*:
 * @target MZ
 * @plugindesc Centre all drawTextEx calls.
 * @author Caethyril
 * @url https://forums.rpgmakerweb.com/threads/161650/
 * @help Free to use and/or modify for any project, no credit required.
 */
// Patch - offset drawTextEx X coordinate to centre.
;void (alias => {
  Window_Base.prototype.drawTextEx = function(text, x, y, width, ...args) {
    if (width === undefined)
      return alias.apply(this, arguments);  // in case no area width is provided
    const textWidth = this.textSizeEx(text).width;
    return alias.call(this,
      text,
      x + Math.floor((width - textWidth) / 2),
      y,
      width,
    ...args);
  };
})(Window_Base.prototype.drawTextEx);
This will cause visible changes (without plugins) for:
  • Help windows (e.g. on save scene)
  • Show Choices
  • Scrolling Text
  • Battle Log
(Show Text uses a slightly different approach, and the associated name box resizes itself to fit the name width.)

Edit: oh I just realised I've been missing the important thing all this time...you wanted it for Show Text, not drawTextEx. :kaoslp:

That would be more challenging, since Show Text processes each character independently. I think you could process the message text line-by-line to decide the newLineX value for each processNewLine, then go ahead and draw the message. Might be easier depending on your current plugins, because as Mac has mentioned, there's no default functionality for aligning text that is processed like this.
 
Last edited:

Ethernite

Game Designer
Member
Joined
Nov 2, 2022
Messages
9
Reaction score
5
First Language
ID / EN
Primarily Uses
RMMZ
Edit: oh I just realised I've been missing the important thing all this time...you wanted it for Show Text, not drawTextEx. :kaoslp:

That would be more challenging, since Show Text processes each character independently. I think you could process the message text line-by-line to decide the newLineX value for each processNewLine, then go ahead and draw the message. Might be easier depending on your current plugins, because as Mac has mentioned, there's no default functionality for aligning text that is processed like this.

I guess I should've told everything from the start...
I didn't use any plugin.
I tried to make a plugin for myself.
I want to replace the current message with my own where it appear by popping in and align to center by default.
The idea is supposed to be simple and everything went well except for aligning this multi-line text to the center.
Every X in each line is tied, so I can't just simply modify the X in processNewLine.
I thought I need every line to be measured before the \n code if it's necessary.
 

caethyril

^_^
Global Mod
Joined
Feb 21, 2018
Messages
5,258
Reaction score
4,732
First Language
EN
Primarily Uses
RMMZ
I thought I need every line to be measured before the \n code if it's necessary.
Yes, you'll need one X value per line.

I spent some time trying things out and came up with this:
JavaScript:
/*:
 * @target MZ
 * @plugindesc Centre all Show Texts.
 * @author Caethyril
 * @url https://forums.rpgmakerweb.com/threads/161650/
 * @help Free to use and/or modify for any project, no credit required.
 */
;void (() => {
"use strict";

  /** Non-conflicting identifier for new "line widths" property on `Window_Message`. */
  const SYM = Symbol();

  /**
   * @param {object} Stores text drawing info.
   * @returns {string} Next/current line of text.
   */
  const getLine = function(textState) {
    const s = textState.text.slice(textState.index);
    const r = /^\n?([^\n]*)\n/.exec(s);
    return r ? r[1] : s;
  };
  
  // Patch - reset starting X value on new line.
  void (alias => {
    Window_Message.prototype.processNewLine = function(textState) {
      delete textState[SYM];
      textState.startX = this.newLineX(textState);
      alias.call(this, textState);
    };
  })(Window_Message.prototype.processNewLine);

  // Override - offset to centre by referencing line width.
  Window_Message.prototype.newLineX = function(textState) {
    // default
    const faceExists = $gameMessage.faceName() !== "";
    const faceWidth = ImageManager.faceWidth;
    const spacing = 20;
    const margin = faceExists ? faceWidth + spacing : 4;
    // get next line's offset (lazy init)
    const lw = textState[SYM] ??= this.textSizeEx(getLine(textState)).width;
    const dx = Math.floor((this.innerWidth - margin - 4 - lw) / 2);
    // text direction
    if (textState.rtl)
      return this.innerWidth - margin - dx;
    return margin + dx;
  };

})();
It did a few quick tests and it seemed OK for me, hopefully it does what you want (or points you in a helpful direction). :kaohi:

(I also noticed that the core message-specific codes, e.g. \! and \$, process even during text measurement...probably an oversight. Could patch the processEscapeCharacter method of Window_Base Window_Message, if necessary, to ensure they only process when textState.drawing is true.)

Edit: here's a snippet to make \! etc not process during Show Text measurement~
JavaScript:
void (alias => {
  Window_Message.prototype.processEscapeCharacter = function(code, textState) {
    if (textState.drawing)
      alias.apply(this, arguments);
    else
      Window_Base.prototype.processEscapeCharacter.apply(this, arguments);
  };
})(Window_Base.prototype.processEscapeCharacter);
You can just add it to the end of the code from the spoiler. :kaophew:
 
Last edited:

Latest Threads

Latest Profile Posts

Larvae.gif
They're larvae, not fightae, honest!
I've made a big emphasis on visually representing things to make the game as accessible as possible.

MP.png

Grimoires will consist of 5 - 10 pages of skills (still finalizing that max number)

Since each actor is able to take multiple actions per turn, each skill will cost 1-5 pages
This prevents more powerful skills from being uber spammed during an actors turn.
Cats are so easy. I noticed the gray one would never nap in the office while I worked, so I put a blanket on the spare chair in here and now she won't leave.
1701793108356.png
still work in progress, had not much time at the weekend^^
Oh deer! Have you checked my calendar today already? ;3
1701790624587.png

Forum statistics

Threads
136,773
Messages
1,269,748
Members
180,514
Latest member
Ikana
Top