4/6/24 v1.0 Latest release
Everything is controlled in the plugin file and through plugin parameters now. No more setting up a parallel common event.
Make an event follow the player's path exactly. This is useful for events
and enemies that chase the player but keep getting caught on corners or behind
walls. By default the last 150 positions the player has been will be saved.
It is not foolproof and events still occasionally get caught on corners if
the player takes a tight turn around a corner, if the player goes over water
or other terrain the follower cannot pass, or another event or obstacle gets in
the event's way
To use put the following code in the event's moveroute
this.followPlayerPath();
or in an event page (if you want to control the event from another event)
this.character(EVENTID).followPlayerPath();
Download the attached .js file OR
Copy and save the following code in a .js file with the name FollowPlayerPathPixel.js in your plugins folder and import it into your project through the plugin manager.
Do not change the file name as it will break the plugin.
Code:
//=============================================================================
// FollowPlayerPathPixel.js (version 1.0)
//=============================================================================
/*:
*@plugindesc Script call to make an event follow the player's path
*@author AquaEcho
*
* @param Tracking Switch ID
* @desc Switch ID to turn on/off player path logging. Leaving this at 0 will make it so the path is always logged.
* @default 0
*
* @param Path Length
* @desc Max number of coordinates stored in the player path
* @default 150
*
*@help
*Make an event follow the player's path exactly. This is useful for events
*and enemies that chase the player but keep getting caught on corners or behind
*walls. By default the last 150 positions the player has been will be saved.
*It is not foolproof and events still occasionally get caught on corners if
*the player takes a tight turn around a corner, if the player goes over water
*or other terrain the follower cannot pass, or another event or obstacle gets in
*the event's way
*
*
*To use put the following code in the event's moveroute
*this.followPlayerPath();
*or in an event page (if you want to control the event from another event)
*this.character(EVENTID).followPlayerPath();
*This plugin uses Restart's distanceToPoint and tLoc functions with
*"Do whatever you want" permissions
*(https://forums.rpgmakerweb.com/index.php?threads/cross-engine-combining-chrono-engine-with-altimit-movement.122622/)
*
*Free for commercial or non-commercial use with credit to AquaEcho and Restart
*/
var AquaEcho = AquaEcho || {};
var AEplayerCoord=[];
AquaEcho.Params = AquaEcho.Params || {};
AquaEcho.SetupParameters = function(){
var parameters = PluginManager.parameters('FollowPlayerPathPixel');
AquaEcho.Params.pathLogSwitch = Number(parameters["Tracking Switch ID"]);
AquaEcho.Params.maxPathLength = Number(parameters["Path Length"]);
}
AquaEcho.SetupParameters();
AquaEcho.setMovementSuccess = Game_Player.prototype.setMovementSuccess;
Game_Player.prototype.setMovementSuccess= function(success) {
if(AquaEcho.Params.pathLogSwitch==0 || (AquaEcho.Params.pathLogSwitch!=0 && $gameSwitches.value(AquaEcho.Params.pathLogSwitch))){
AEplayerCoord.push([$gamePlayer.x, $gamePlayer.y]);
//save up to maxPathLength coordinates, dump the oldest 1/3 if more than that
if (AEplayerCoord.length > AquaEcho.Params.maxPathLength) {
AEplayerCoord.splice(0, AquaEcho.Params.maxPathLength/3);
}
}
};
AquaEcho.reserveTransfer = Game_Player.prototype.reserveTransfer;
Game_Player.prototype.reserveTransfer = function(mapId, x, y, d, fadeType) {
AquaEcho.reserveTransfer.apply(this, arguments);
AEplayerCoord=[];
};
Game_CharacterBase.prototype.followPlayerPath = function(){
//Find the closest coordinates to the current event in the playerCoordinates array
var closestX;
var closestY;
var closestDistance = Infinity;
var closestArrayPosition;
for (var i = 0; i < AEplayerCoord.length; i++) {
var x = AEplayerCoord[i][0];
var y = AEplayerCoord[i][1];
var distance = Math.sqrt((x - this.x) ** 2 + (y - this.y) ** 2);
if (distance < closestDistance) {
closestX = x;
closestY = y;
closestDistance = distance;
closestArrayPosition = i;
}
}
//Make current event go to the closest coordinates
this.tLoc(closestX, closestY, true);
//When it reaches the coordinates make it go to the next position in the array, then the next, etc.
for (var j = closestArrayPosition; j < AEplayerCoord.length; j++) {
if(this.distanceToPoint(closestX,closestY)<=.5){
closestX = AEplayerCoord[closestArrayPosition][0];
closestY = AEplayerCoord[closestArrayPosition][1];
this.tLoc(closestX, closestY, true);
closestArrayPosition++;
}
}
}
//calculates the distance from an event to a given point. @author Restart
Game_CharacterBase.prototype.distanceToPoint = function(xcoord,ycoord)
{
var distance = Math.sqrt( (this.x-xcoord)*(this.x-xcoord) + (this.y-ycoord)*(this.y-ycoord) );
return distance;
}
//sets target location to coordinates (short so can see in movement route window) @author Restart
Game_CharacterBase.prototype.tLoc = function(xcoord,ycoord,skippable)
{
this._moveTargetX = xcoord;
this._moveTargetY = ycoord;
this.setDirectionVector(xcoord-this.x,ycoord-this.y); // turn
this._moveTarget = true;
if (skippable==undefined)
{
this._moveTargetSkippable = true;
}else{
this._moveTargetSkippable = skippable;
}
}
//._inMotion @author Restart
var Game_CharacterBase_update_for_ismoving = Game_CharacterBase.prototype.update;
Game_CharacterBase.prototype.update = function() {
//.isMoving doesn't really work in altimit
//this fixes it with the addition of a new function which I can use to tell
//if the character is actually like, moving
// the problem seems to be that the isMoving gets cleared midway through
// this update step (because the .updateMove in rpg_objects sets ._realX to equal .x)
// but lots of things break if I monkey around with _isMoving
// so I'm creating my own clone of it here.
// this is true if the character is in motion and false if they aren't.
if (this.isMoving())
{
this._inMotion=true;
}else{
this._inMotion=false;
}
Game_CharacterBase_update_for_ismoving.call( this );
}You're free to use it commercially, non-commercially, or edit it as long as you credit me and Restart since it uses several of his functions.