Foreground Parallax for MZ (Updated With Lock Parallax Option)

Lion Blade Soler

Autistic Artist
Veteran
Joined
Mar 15, 2012
Messages
85
Reaction score
76
First Language
Portuguese
Primarily Uses
RMMV
Years ago, I created a VX Ace script for fog effects, which was a feature that existed on RPG Maker XP but that was absent on VX Ace. The only time that I have ever shown the script was on the Facebook page for RPG Maker Web, but I have never bothered to post the script on the RPG Maker Forum before and have started to become more involved with the community only lately, especially due to being excited with the release of RPG Maker MZ. As a result, I improved my fog script for VX Ace and used that as a blueprint for the Foreground Parallax plugin for RPG Maker MV, which would in turn be converted into the Foreground Parallax plugin for RMMZ. With the backstory out of the way, I will now introduce to you the Foreground Parallax plugin that I created for MZ. For the record, I'm aware that there are other people that have created their own Foreground Parallax plugins and that one of those plugins came with RMMZ as a launch plugin, but I wanted to be more involved with the RPG Maker/game designer community, which was/is why I created the Foreground Parallax plugin for RMMZ. The following image is the screenshot of the Plugin Settings that shows the Foreground Parallax plugin as a selected plugin.

ForegroundParallaxPlugin.png

If you look at the Author section, you will notice that I didn't credit myself as the author of the plugin and did so out of my own choice. I want for this plugin to be an open source plugin as well as a copyleft plugin, so I'm not claiming copyright on the plugin and everyone have full permission to modify the plugin as well as take credit for the plugin if any modification (especially a big modification) was done to it. When I created the fog script for VX Ace and the Foreground Parallax for RMMV, I made sure that they would be accessible through the Script Event Command as I wanted for the Fog/Foreground Parallax to be like an Event Command and part of RMVX Ace/RMMV. Unlike the previous two versions of the Foreground Parallax code (either as a script or as a plugin), the Foreground Parallax plugin for MZ is accessible through the Plugin Command Event Command. I wanted to take full advantage of the improvement on the Plugin Command for RMMZ and make the plugin accessible to everyone, so there would be no need to use a script line to activate/deactivate the foreground parallax (which could/would also lead to error(s) if the line of code was typed or inputted incorrectly). The following screenshot shows how the Plugin Command for the Foreground Parallax should look like.

ForegroundParallaxPluginCommand.png

The Command Name is Show Foreground Parallax and the screenshot that you are seeing was/is an example of the inputted information for the parameters. The default input for the parameters will be different, and if you want for no foreground parallax to be shown, then you can either leave the Foreground Parallax name as blank or set the opacity to 0. Speaking of opacity, that's the one parameter that I wanted to see present on the plugin as RMXP did have opacity control for the fog. Now, the following screenshot shows the Foreground Parallax in action.

ForegroundParallaxSample.png

When I created the Foreground Parallax as an Event, I treated the Event as a "dummy" event and placed the Event on the top left corner. I made sure that the Options (especially Walking) were deactivated as there was no need for the Options, and just to be on the safe side (even if there was no need to do that), I have set the Event as "Above characters". However, the Trigger was set to Parallel in order for the Event to work. Of course, the example was/is a basic way to use Foreground Parallax plugin. I have attached the file of the Foreground Parallax plugin to this post, but even so, I'll be posting the code for the plugin in here as well, so that everyone will have a chance to look at how the code looks like.

JavaScript:
//=============================================================================
// ForegroundParallax.js
//=============================================================================

/*:
* @target MZ
* @plugindesc Shows foreground parallax that can be used for fogs.
* @author N/A (open-source, copyleft)
*
* @help ForegroundParallax.js
*
* This plugin provides a command for showing the foreground parallax.  The
* opacity of the foreground parallax has to be higher than 0 in order for
* the foreground parallax to be visible.  The foreground parallax becomes
* more visible with a very high opacity.
*
* @command on
* @text Show Foreground Parallax
* @desc Shows the foreground parallax
*
* @arg parallaxName
* @type string
* @default
* @text Foreground Parallax
* @desc Filename of the parallax image
*
* @arg lockParallax
* @type boolean
* @on On
* @off Off
* @default false
* @text Lock Parallax
* @desc Keep the Foreground Parallax in locked position
*
* @arg loopHorizontally
* @type boolean
* @on On
* @off Off
* @default false
* @text Loop Horizontally
* @desc Turns Loop Horizontally on/off
*
* @arg loopVertically
* @type boolean
* @on On
* @off Off
* @default false
* @text Loop Vertically
* @desc Turns Loop Vertically on/off
*
* @arg scrollX
* @type number
* @min -32
* @max 32
* @default 0
* @text Horizontal Scroll
* @desc Horizontal scroll value (-32 - 32)
*
* @arg scrollY
* @type number
* @min -32
* @max 32
* @default 0
* @text Vertical Scroll
* @desc Vertical scroll value (-32 - 32)
*
* @arg parallaxOpacity
* @type number
* @min 0
* @max 255
* @default 64
* @text Opacity
* @desc Opacity of the parallax foreground (0 - 255)
*/

(() => {
      //-----------------------------------------------------------------------------
    // PluginManager
    //
  
      const pluginName = "ForegroundParallax";

    PluginManager.registerCommand(pluginName, "on", args => {
        name = String(args.parallaxName);
        lock = eval(args.lockParallax);
        loopX = eval(args.loopHorizontally);
        loopY = eval(args.loopVertically);
        sx = Number(args.scrollX);
        sy = Number(args.scrollY);
        opacity = Number(args.parallaxOpacity);
        $gameMap.showFog(name, lock, loopX, loopY, sx, sy, opacity);
    });
  
    //-----------------------------------------------------------------------------
    // Game_Map
    //
    // The game object class for a map. It contains scrolling and passage
    // determination functions.
  
    Game_Map.prototype.initialize = function() {
        this._interpreter = new Game_Interpreter();
        this._mapId = 0;
        this._tilesetId = 0;
        this._events = [];
        this._commonEvents = [];
        this._vehicles = [];
        this._displayX = 0;
        this._displayY = 0;
        this._nameDisplay = true;
        this._scrollDirection = 2;
        this._scrollRest = 0;
        this._scrollSpeed = 4;
        this._parallaxName = '';
        this._parallaxZero = false;
        this._parallaxLoopX = false;
        this._parallaxLoopY = false;
        this._parallaxSx = 0;
        this._parallaxSy = 0;
        this._parallaxX = 0;
        this._parallaxY = 0;
        this._fogName = '';
        this._fogZero = false;
        this._fogLoopX = false;
        this._fogLoopY = false;
        this._fogSx = 0;
        this._fogSy = 0;
        this._fogX = 0;
        this._fogY = 0;
        this._fogOpacity = 0;
        this._battleback1Name = null;
        this._battleback2Name = null;
        this.createVehicles();
    };
  
    Game_Map.prototype.setup = function(mapId) {
        if (!$dataMap) {
            throw new Error('The map data is not available');
        }
        this._mapId = mapId;
        this._tilesetId = $dataMap.tilesetId;
        this._displayX = 0;
        this._displayY = 0;
        this.refereshVehicles();
        this.setupEvents();
        this.setupScroll();
        this.setupParallax();
        this.setupFog();
        this.setupBattleback();
        this._needsRefresh = false;
    };
  
    Game_Map.prototype.fogName = function() {
        return this._fogName;
    };
  
    Game_Map.prototype.fogOpacity = function() {
        return this._fogOpacity;
    };
  
    Game_Map.prototype.setupFog = function() {
        this._fogName = "";
        this._fogZero = false;
        this._fogLoopX = false;
        this._fogLoopY = false;
        this._fogSx = 0;
        this._fogSy = 0;
        this._fogX = 0;
        this._fogY = 0;
        this._fogOpacity = 0;
    };
  
    Game_Map.prototype.setDisplayPos = function(x, y) {
        if (this.isLoopHorizontal()) {
            this._displayX = x.mod(this.width());
            this._parallaxX = x;
            this._fogX = x;
        } else {
            var endX = this.width() - this.screenTileX();
            this._displayX = endX < 0 ? endX / 2 : x.clamp(0, endX);
            this._parallaxX = this._displayX;
            this._fogX = this._displayX;
        }
        if (this.isLoopVertical()) {
            this._displayY = y.mod(this.height());
            this._parallaxY = y;
            this._fogY = y;
        } else {
            var endY = this.height() - this.screenTileY();
            this._displayY = endY < 0 ? endY / 2 : y.clamp(0, endY);
            this._parallaxY = this._displayY;
            this._fogY = this._displayY;
        }
    };
  
    Game_Map.prototype.fogOx = function() {
        if (this._fogZero) {
            return this._fogX * this.tileWidth();
        } else if (this._fogLoopX) {
            return this._fogX * this.tileWidth() / 2;
        } else {
            return 0;
        }
    };
  
    Game_Map.prototype.fogOy = function() {
        if (this._fogZero) {
            return this._fogY * this.tileHeight();
        } else if (this._fogLoopY) {
            return this._fogY * this.tileHeight() / 2;
        } else {
            return 0;
        }
    };
  
    Game_Map.prototype.scrollDown = function(distance) {
        if (this.isLoopVertical()) {
            this._displayY += distance;
            this._displayY %= $dataMap.height;
            if (this._parallaxLoopY) {
                this._parallaxY += distance;
            }
            if (this._fogLoopY) {
                this._fogY += distance;
            }
        } else if (this.height() >= this.screenTileY()) {
            var lastY = this._displayY;
            this._displayY = Math.min(
                this._displayY + distance,
                this.height() - this.screenTileY()
            );
            this._parallaxY += this._displayY - lastY;
            this._fogY += this._displayY - lastY;
        }
    };
  
    Game_Map.prototype.scrollLeft = function(distance) {
        if (this.isLoopHorizontal()) {
            this._displayX += $dataMap.width - distance;
            this._displayX %= $dataMap.width;
            if (this._parallaxLoopX) {
                this._parallaxX -= distance;
            }
            if (this._fogLoopX) {
                this._fogX -= distance;
            }
        } else if (this.width() >= this.screenTileX()) {
            var lastX = this._displayX;
            this._displayX = Math.max(this._displayX - distance, 0);
            this._parallaxX += this._displayX - lastX;
            this._fogX += this._displayX - lastX;
        }
    };
  
    Game_Map.prototype.scrollRight = function(distance) {
        if (this.isLoopHorizontal()) {
            this._displayX += distance;
            this._displayX %= $dataMap.width;
            if (this._parallaxLoopX) {
                this._parallaxX += distance;
            }
            if (this._fogLoopX) {
                this._fogX += distance;
            }
        } else if (this.width() >= this.screenTileX()) {
            var lastX = this._displayX;
            this._displayX = Math.min(
                this._displayX + distance,
                this.width() - this.screenTileX()
            );
            this._parallaxX += this._displayX - lastX;
            this._fogX += this._displayX - lastX;
        }
    };
  
    Game_Map.prototype.scrollUp = function(distance) {
        if (this.isLoopVertical()) {
            this._displayY += $dataMap.height - distance;
            this._displayY %= $dataMap.height;
            if (this._parallaxLoopY) {
                this._parallaxY -= distance;
            }
            if (this._fogLoopY) {
                this._fogY -= distance;
            }
        } else if (this.height() >= this.screenTileY()) {
            var lastY = this._displayY;
            this._displayY = Math.max(this._displayY - distance, 0);
            this._parallaxY += this._displayY - lastY;
            this._fogY += this._displayY - lastY;
        }
    };
  
    var _Game_Map_update = Game_Map.prototype.update;
    Game_Map.prototype.update = function(sceneActive) {
        _Game_Map_update.call(this, sceneActive);
        this.updateFog();
    };
  
    Game_Map.prototype.updateFog = function() {
        if (this._fogLoopX) {
            this._fogX -= this._fogSx / this.tileWidth() / 2;
        }
        if (this._fogLoopY) {
            this._fogY -= this._fogSy / this.tileHeight() / 2;
        }
    };
  
    Game_Map.prototype.showFog = function(name, lock, loopX, loopY, sx, sy, opacity) {
        this._fogName = name;
        this._fogZero = lock;
        if (this._fogLoopX && !loopX) {
            this._fogX = 0;
        }
        if (this._fogLoopY && !loopY) {
            this._fogY = 0;
        }
        this._fogLoopX = loopX;
        this._fogLoopY = loopY;
        this._fogSx = sx;
        this._fogSy = sy;
        this._fogOpacity = opacity;
    };
  
    //-----------------------------------------------------------------------------
    // Spriteset_Map
    //
    // The set of sprites on the map screen.
  
    var _Spriteset_Map_createLowerLayer = Spriteset_Map.prototype.createLowerLayer;
    Spriteset_Map.prototype.createLowerLayer = function() {
        _Spriteset_Map_createLowerLayer.call(this);
        this.createFog();
    };
  
    var _Spriteset_Map_update = Spriteset_Map.prototype.update;
    Spriteset_Map.prototype.update = function() {
        _Spriteset_Map_update.call(this);
        this.updateFog();
    };
  
    Spriteset_Map.prototype.createFog = function() {
        this._fog = new TilingSprite();
        this._fog.move(0, 0, Graphics.width, Graphics.height);
        this._baseSprite.addChild(this._fog);
    };
  
    Spriteset_Map.prototype.updateFog = function() {
        if (this._fogName !== $gameMap.fogName()) {
            this._fogName = $gameMap.fogName();
            this._fog.bitmap = ImageManager.loadParallax(this._fogName);
        }
        if (this._fog.bitmap) {
            this._fog.origin.x = $gameMap.fogOx();
            this._fog.origin.y = $gameMap.fogOy();
            this._fog.opacity = $gameMap.fogOpacity();
        }
    };
})();

Once again, the plugin is open source and copyleft, so there's no need to give me credit for it and you can alter the plugin with full permission.

UPDATE: The Lock Parallax option has been added to the plugin. Also, some fixes and improvements were done on the plugin.
 

Attachments

Last edited:

Lion Blade Soler

Autistic Artist
Veteran
Joined
Mar 15, 2012
Messages
85
Reaction score
76
First Language
Portuguese
Primarily Uses
RMMV
UPDATE: There was a mistake on the code that I overlooked (I forgot to include @ in front of the word default under the Parallax Name argument), so I updated the code within the spoiler tag as well as deleted the original plugin attached to this post and uploaded the updated plugin with the fix and with other minor additions and changes.
 
Last edited:

ThePedro004

Villager
Member
Joined
Oct 11, 2015
Messages
18
Reaction score
10
First Language
Portuguese
Primarily Uses
RMMZ
That is really nice but the images doesnt bind to the map, when the camera moves, the image moves with it, could you fix it?
 

Lion Blade Soler

Autistic Artist
Veteran
Joined
Mar 15, 2012
Messages
85
Reaction score
76
First Language
Portuguese
Primarily Uses
RMMV
That is really nice but the images doesnt bind to the map, when the camera moves, the image moves with it, could you fix it?
I used the background parallax as the original basis for the foreground parallax, but having said that, I did notice that the foreground parallax on RPG Maker XP (where the foreground parallax is known as fog) tends to have its own math instead of having the same math as the background parallax (a.k.a. panorama on RMXP). I will see what I can do and try to post an updated version of the plugin as soon as possible.
 

Logica

Let's go to paradise!
Veteran
Joined
Jun 25, 2012
Messages
45
Reaction score
59
First Language
Portugues
Primarily Uses
RMMV
Man this is really cool! Really good! I was in need of something like this for my project!I insist on putting your name in the credits of my project! Thanks for making it available!
 

ThePedro004

Villager
Member
Joined
Oct 11, 2015
Messages
18
Reaction score
10
First Language
Portuguese
Primarily Uses
RMMZ
I used the background parallax as the original basis for the foreground parallax, but having said that, I did notice that the foreground parallax on RPG Maker XP (where the foreground parallax is known as fog) tends to have its own math instead of having the same math as the background parallax (a.k.a. panorama on RMXP). I will see what I can do and try to post an updated version of the plugin as soon as possible.
Looking foward for this!
 

Lion Blade Soler

Autistic Artist
Veteran
Joined
Mar 15, 2012
Messages
85
Reaction score
76
First Language
Portuguese
Primarily Uses
RMMV
Man this is really cool! Really good! I was in need of something like this for my project!I insist on putting your name in the credits of my project! Thanks for making it available!
No problem! There's still no need to give me credit for the plugin, but I appreciate it :rswt. Also, I want to give you, @ThePedro004, and anyone else that's reading this a heads up: I updated the code under the spoiler tag as well as reuploaded the plugin with a small update. I still need to see what else I can do to improve the plugin, but for now, I changed the updateFog function to be less like the updateParallax function by changing the "+" to "-" and by getting rid of "/ 2" on the two equations. By doing that, the scrolling of the foreground parallax won't be completely affected by the scrolling movement of the map/camera. Before the change, the foreground parallax did have a similar problem that the background parallax has when it came to scrolling, but getting rid of the "/ 2" on both equations did help solve the problem a bit; the other change is for making the foreground parallax distinguish itself from the background parallax, like it was done on RMXP.

EDIT - P.S.: I forgot to mention that the new update does make the foreground parallax slightly faster, so you will have to be careful with the value choice for scrolling.
 
Last edited:

Lion Blade Soler

Autistic Artist
Veteran
Joined
Mar 15, 2012
Messages
85
Reaction score
76
First Language
Portuguese
Primarily Uses
RMMV
Last week, @ThePedro004 made a request to make the foreground parallax not be bound to the map, and as far as I noticed, I managed to accomplish making that happen. Now, before I continue, I would like to give credit to @Archeia for indirectly showing me the trick behind locking the parallaxes. Archeia pointed out to someone through the Steam Forum that a parallax can be locked in when "!" is placed in front of the name of the parallax filename. I decided to give using "!" on the filename a try and it definitely gave the result that I was looking for. After that, I decided to look through the code and see how the whole thing worked, and after I saw that the isZeroParallax function was what played a role on making a parallax image be locked in whenever the exclamation point is typed in front of the filename of the parallax image, I decided to add a new option to the plugin as an alternative to the isZeroParallax function and that option is Lock Parallax. With Lock Parallax, there's no need to type an exclamation point in front of the parallax filename when it comes to the foreground parallax; the foreground parallax will still scroll when the information for scrolling is set, but the foreground parallax will be locked in whenever the Lock Parallax is turned On.

In addition to the Lock Parallax option, I made some changes and fixes to the plugin. While adding the Lock Parallax function and testing it, I didn't realize that there couple flaws to the plugin due to the boolean arguments not working as intended. The problem has been fixed and the boolean arguments/options (which are the On/Off switches) are now working as intended. By the way, I put "/ 2" back on the two equations from updateFog, since the Lock Parallax option resolved the issue of the foreground parallax being bound to the map.
 

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

Latest Threads

Latest Posts

Latest Profile Posts

"You can thank my later", "But you haven't done anything", "Well, that's why ..."
Are we allowed to post about non-RPG Maker games?
I should realize that error was produced by a outdated version of MZ so that's why it pop up like that
Ami
i can't wait to drink some ice after struggling with my illness in 9 days. 9 days is really bad for me,i can't focus with my shop and even can't do something with my project
How many hours have you got in mz so far?

Forum statistics

Threads
105,884
Messages
1,017,242
Members
137,609
Latest member
shododdydoddy
Top