[RMMV] How to flip (mirror) SV Battlers Left/Right with Yanfly Plugins

Moon_Haven

Veteran
Veteran
Joined
May 5, 2020
Messages
81
Reaction score
35
First Language
English
Primarily Uses
RMMV
[EDIT: This seems to be working, so I've changed the title from "need help" to "how to". I kept the rest of my post intact so future dwellers can learn about the process and have the code]



Hello. I need help.

So far, I've been able to reposition actors to the left of the screen, and the enemies on the right. In order to make all of them attack in the correct direction, I have changed the parameters of this.setMirror to true in the CODE of YEP_BattleEngineCore

JavaScript:
Game_Battler.prototype.spriteFaceForward = function() {
    this.setMirror(true);
};

Game_Battler.prototype.spriteFaceBackward = function() {
    this.setMirror(true);
This makes the battlers face the targets properly, swing weapons in the right direction, etc.

Where I'm stuck: The only thing that I'm not able to figure out is that at the beginning of the battle, every battler is looking in the wrong direction (picture below).

mirror.png

But once the battle begins, things come to normal. For actors: they all turn in the right direction after the first action input (so when they move back to their home position). For the enemies, when the last actor has set its action, all the enemies turn around all at once.

I have the feeling I need to inject some kind of a refresh at the very beginning of the battle (force a this.spriteFaceForward() on each battler), or set a default parameter when the battlers are initialized. I just do not know where. Been trying for a couple of days :(

flipped.png

Here's basically a step-by-step how I got here:

Notes:
- I'm using Yanfly plugins.
- I'm using screen size of 1280 x 720. You can use pretty much any size that you want, but you will need to change the hard values (150, 26, 52...) to fit your game screen size.

STEP 1 - Position our actors and enemies.
I used YEP_RowFormation to automate the positions. My game will use 3 rows for actors and enemies. Row1 (fighters) is at the front, Row2 (support) is middle, Row3 (casters) is at the back.

rows.png

The values below assume that the sprites are 64x64. If they are any bigger, you will want to change the values of 16, 32 and 64.
The value 150 is the distance from the edge of the screen.
The values 26 and 52 are for the staggering. Simply put, we add (or retract) these values for each sprite on a row, so that it gives a sense of perspective. These will need to be changed (trial and error) if you use a different screen size than 1280 x 720. If you are using default RMMV size, you can use 16 and 32 as a starting point. This is what it would look like.

In YEP_RowFormation:
Maximum Rows
: 3
Maximum Row X: screenWidth - 150 + 26
Maximum Row Y: screenHeight - statusHeight - 16
Minimum Row Y: screenHeight - statusHeight - 16 - ((maxRows + 1) * 64)
Center Row Y: (maxRowY + minRowY) / 2 + 16

Row 1 Home X: 150 - 32 + $gameParty.rowSize(maxRows) * 26 + (maxRows - rowId) * 150 - $gameParty.rowSize(rowId) * 26 + rowIndex * 52
Row 1 Home Y: centerY - ((rowSize / -2 + 0.5) + rowIndex) * 64
Row 2 Home X: 150 - 32 + $gameParty.rowSize(maxRows) * 26 + (maxRows - rowId) * 150 - $gameParty.rowSize(rowId) * 26 + rowIndex * 52
Row 2 Home Y: centerY - ((rowSize / -2 + 0.5) + rowIndex) * 64
Row 3 Home X: 150 - 32 + $gameParty.rowSize(maxRows) * 26 + (maxRows - rowId) * 150 - $gameParty.rowSize(rowId) * 26 + rowIndex * 52
Row 3 Home Y: centerY - ((rowSize / -2 + 0.5) + rowIndex) * 64
Enemy Row X: screenWidth - 150 + 32 - $gameTroop.rowSize(maxRows) * 26 - (maxRows - rowId) * 150 + $gameTroop.rowSize(rowId) * 26 - rowIndex * 52
Enemy Row Y: centerY - ((rowSize / -2 + 0.5) + rowIndex) * 64


STEP 2 - Flip (mirror) the sprites
Now that I have positioned the actors where the enemies should be, and vice-versa, the sprites are looking in the wrong direction. To fix this:

In YEP_BattleEngineCore:

Step Distance
: -32
Flinch Distance: -16

In the *CODE* of YEP_BattleEngineCore.js:
I switched the values for mirroring. Find the following lines:

JavaScript:
Game_Battler.prototype.spriteFaceForward = function() {
    this.setMirror(false);
};
Game_Battler.prototype.spriteFaceBackward = function() {
    this.setMirror(true);
};
Change the false to true, and true to false

JavaScript:
Game_Battler.prototype.spriteFaceForward = function() {
    this.setMirror(true);  // Default: false
};
Game_Battler.prototype.spriteFaceBackward = function() {
    this.setMirror(false);   // Default: true
};

STEP 3 - Action Sequence (no longer needed, code in 3rd post of this thread fixes all of this)
Everything is now reversed, even action sequence. For instance, moving an actor to the front of an enemy was: move user: target, front, 30 but is it now: move user: target, back, 30

A simple attack will now look like this:
Code:
<setup action>
    clear battle log
    display action
    immortal: targets, true
    cast animation
    wait for animation
</setup action>

<whole action>
    face user: target
    if user.attackMotion() !== 'missile'
        move user: target, back, 30
        wait for movement
    else
        perform start
        wait for movement
    end
</whole action>

<target action>
    motion attack: user
    wait: 10
    action effect
    if target.result().missed || target.result().evaded
    else
        attack animation: target
        wait for animation
    end
</target action>

<finish action>
    immortal: targets, false
    wait for new line
    clear battle log
    perform finish
    wait for movement
    wait for effect
</finish action>
 
Last edited:

Moon_Haven

Veteran
Veteran
Joined
May 5, 2020
Messages
81
Reaction score
35
First Language
English
Primarily Uses
RMMV
I've modified a line of code in the YEP_RowFormation, which effectively forces mirroring.


In the *CODE* YEP_RowFormation.js:
Look for this:
JavaScript:
BattleManager.refreshAllBattlers = function() {
  var members = $gameParty.members().concat($gameTroop.members());
  var length = members.length;
  for (var i = 0; i < length; ++i) {
    var member = members[i];
    if (member){
      member.refresh();
    }
  }
};
... and add member.setMirror(true); under the member.refresh(), like so:

JavaScript:
BattleManager.refreshAllBattlers = function() {
  var members = $gameParty.members().concat($gameTroop.members());
  var length = members.length;
  for (var i = 0; i < length; ++i) {
    var member = members[i];
    if (member){
      member.refresh();
      member.setMirror(true);
    }
  }
};
 
Last edited:

Moon_Haven

Veteran
Veteran
Joined
May 5, 2020
Messages
81
Reaction score
35
First Language
English
Primarily Uses
RMMV
I did some additional work on this as the battlers were mixing up FRONT and BACK. The additional changes you need to do are:

In the *CODE* of YEP_X_ActSeqPack2.js:
Replace the whole BattleManager.actionFace with this:

JavaScript:
BattleManager.actionFace = function(name, actionArgs) {
    var movers = this.makeActionTargets(name);
    if (movers.length < 1) return true;
    var cmd = actionArgs[0].toUpperCase();
    if (['FORWARD', 'NORMAL'].contains(cmd)) {
      movers.forEach(function(mover) {
        mover.spriteFaceForward();
      });
    } else if (['BACKWARD', 'MIRROR'].contains(cmd)) {
      movers.forEach(function(mover) {
        mover.spriteFaceBackward();
      });
    } else if (['HOME', 'ORIGIN'].contains(cmd)) {
      movers.forEach(function(mover) {
        mover.spriteFaceHome();
      });
    } else if (['AWAY FROM HOME', 'AWAY FROM ORIGIN'].contains(cmd)) {
      movers.forEach(function(mover) {
        mover.spriteFaceAwayHome();
      });
    } else if (['POINT', 'POSITION', 'COORDINATE', 'SCREEN', 'SCREEN POS',
    'COORDINATES'].contains(cmd)) {
      var destX = eval(actionArgs[1]) || 0;
      var destY = eval(actionArgs[2]) || 0;
      movers.forEach(function(mover) {
        // mover.spriteFacePoint(destX, destY);
        mover.spriteFaceAwayPoint(destX, destY);
      });
    } else if (['AWAY FROM POINT', 'AWAY FROM POSITION', 'AWAY FROM COORDINATE',
    'AWAY FROM SCREEN', 'AWAY FROM SCREEN POS',
    'AWAY FROM COORDINATES'].contains(cmd)) {
      var destX = eval(actionArgs[1]) || 0;
      var destY = eval(actionArgs[2]) || 0;
      movers.forEach(function(mover) {
        // mover.spriteFaceAwayPoint(destX, destY);
        mover.spriteFacePoint(destX, destY);
      });
    } else if (cmd.match(/AWAY[ ]FROM[ ](.*)/i)) {
      var targets = this.makeActionTargets(String(RegExp.$1));
      if (targets.length < 1) return false;
      var destX = 0;
      var destY = 0;
      targets.forEach(function(target) {
        destX += target.spritePosX();
        destY += target.spritePosY();
      }, this);
      destX /= targets.length;
      destY /= targets.length;
      movers.forEach(function(mover) {
        // mover.spriteFaceAwayPoint(destX, destY);
        mover.spriteFacePoint(destX, destY);
      }, this);
    } else {
      var targets = this.makeActionTargets(actionArgs[0]);
      if (targets.length < 1) return false;
      var destX = 0;
      var destY = 0;
      targets.forEach(function(target) {
        destX += target.spritePosX();
        destY += target.spritePosY();
      }, this);
      destX /= targets.length;
      destY /= targets.length;
      movers.forEach(function(mover) {
        // mover.spriteFacePoint(destX, destY);
        mover.spriteFaceAwayPoint(destX, destY);
      }, this);
    }
    return false;
};


Replace the whole BattleManager.actionMove with this:

JavaScript:
BattleManager.actionMove = function(name, actionArgs) {
    if (!$gameSystem.isSideView()) return true;
    var movers = this.makeActionTargets(name);
    if (movers.length < 1) return true;
    var cmd = actionArgs[0].toUpperCase();

    if (['HOME', 'ORIGIN'].contains(cmd)) {
      var frames = actionArgs[1] || 12;
      movers.forEach(function(mover) {
        mover.battler().startMove(0, 0, frames);
        mover.requestMotion('walk');
        mover.spriteFaceHome();
      });
    } else if (['RETURN'].contains(cmd)) {
      var frames = actionArgs[1] || 12;
      movers.forEach(function(mover) {
        mover.battler().startMove(0, 0, frames);
        mover.requestMotion('evade');
        mover.spriteFaceForward();
      });
    } else if (['FORWARD', 'FORWARDS', 'BACKWARD',
    'BACKWARDS'].contains(cmd)) {
      var distance = actionArgs[1] || Yanfly.Param.BECStepDist;
      if (['BACKWARD', 'BACKWARDS'].contains(cmd)) distance *= -1;
      var frames = actionArgs[2] || 12;
      movers.forEach(function(mover) {
        mover.battler().moveForward(distance, frames);
        mover.requestMotion('walk');
        if (['FORWARD', 'FORWARDS'].contains(cmd)) {
          mover.spriteFaceForward();
        } else {
          mover.spriteFaceBackward();
        }
      });
    } else if (['POINT', 'POSITION', 'COORDINATE', 'SCREEN', 'SCREEN POS',
    'COORDINATES'].contains(cmd)) {
      var destX = eval(actionArgs[1]) || 0;
      var destY = eval(actionArgs[2]) || 0;
      var frames = actionArgs[3] || 12;
      movers.forEach(function(mover) {
        var offsetX = BattleManager.actionMoveOffsetX(actionArgs, mover, mover);
        var offsetY = BattleManager.actionMoveOffsetY(actionArgs, mover, mover);
        mover.battler().moveToPoint(destX + offsetX, destY + offsetY, frames);
        mover.requestMotion('walk');
        mover.spriteFacePoint(destX, destY);      
      });
    } else {
      var targets = this.makeActionTargets(actionArgs[0]);
      var frames = actionArgs[2] || 12;
      var type = actionArgs[1].toUpperCase();
      if (targets.length < 1) return false;
      for (var i = 0; i < movers.length; ++i) {
          var mover = movers[i];
          if (!mover) continue;
          if (['BASE', 'FOOT', 'FEET'].contains(type)) {
            var destX = this.actionMoveX(mover, targets, 'center');
            var destY = this.actionMoveY(mover, targets, 'foot');
          } else if (['CENTER', 'MIDDLE'].contains(type)) {
            var destX = this.actionMoveX(mover, targets, 'center');
            var destY = this.actionMoveY(mover, targets, 'center');
          } else if (['HEAD', 'TOP'].contains(type)) {
            var destX = this.actionMoveX(mover, targets, 'center');
            var destY = this.actionMoveY(mover, targets, 'head');
          } else if (['FRONT BASE', 'FRONT FOOT', 'FRONT FEET',
          'FRONT'].contains(type)) {
            var destX = this.actionMoveX(mover, targets, 'back'); // FRONT <-> BACK -- WORKS
            var destY = this.actionMoveY(mover, targets, 'foot');
          } else if (['BACK BASE', 'BACK FOOT', 'BACK FEET',
          'BACK'].contains(type)) {
              var destX = this.actionMoveX(mover, targets, 'front'); // FRONT <-> BACK -- WORKS
            var destY = this.actionMoveY(mover, targets, 'foot');
          } else if (['FRONT CENTER', 'FRONT MIDDLE'].contains(type)) {
            var destX = this.actionMoveX(mover, targets, 'back'); // FRONT <-> BACK -- WORKS
            var destY = this.actionMoveY(mover, targets, 'center');
          } else if (['BACK CENTER', 'BACK MIDDLE',].contains(type)) {
            var destX = this.actionMoveX(mover, targets, 'front'); // FRONT <-> BACK -- WORKS
            var destY = this.actionMoveY(mover, targets, 'center');
          } else if (['FRONT HEAD', 'FRONT TOP'].contains(type)) {
            var destX = this.actionMoveX(mover, targets, 'back'); // FRONT <-> BACK -- WORKS
            var destY = this.actionMoveY(mover, targets, 'head');
          } else if (['BACK HEAD', 'BACK TOP'].contains(type)) {
            var destX = this.actionMoveX(mover, targets, 'front'); // FRONT <-> BACK -- WORKS
            var destY = this.actionMoveY(mover, targets, 'head');
          }
        var offsetX = this.actionMoveOffsetX(actionArgs, mover, targets[0]);
        var offsetY = this.actionMoveOffsetY(actionArgs, mover, targets[0]);
          mover.battler().moveToPoint(destX + offsetX, destY + offsetY, frames);
        // mover.spriteFacePoint(destX, destY);
        mover.spriteFaceAwayPoint(destX, destY);
      }
    }
    return true;
};
 

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

Latest Threads

Latest Posts

Latest Profile Posts

One 3-day jam and a Game Awards... this month is moving... \o/
Maker-ing has been being the best thing that happened to me this year so far. it is so good to rescue some old skills fo creativity and the people I have met are really incredible. I love my coffelanders and tocudos buddies. Maybe one day I will reach other countries folks too. S2
Well... My game plays better at 1920x1080, so I guess that's the new resolution. Still runs at 60FPS. :LZSexcite: Also... I really want a boss to be able to build new maps around the player... Mostly because it's visually spectacular! I'm er... not quite sure yet how I can do that without making MV explode.... But I'll find a way, anything in service to the "sparkles"! :kaopride:
How to change your netbooks screen resolution

Forum statistics

Threads
100,791
Messages
979,588
Members
132,436
Latest member
jefigeb851
Top