admin管理员组

文章数量:1313599

Ok, So I have a script in .js for rpg maker. I am trying to move the actor to target - attack animation - return to original position. However, the best I have had is Attack - Dash to target - dash back.

I cannot seem to overwrite the attack animation with the dash forward first.

I have tried different approaches such as asynchronous, waits etc, but no matter what, it is always attack - dash - dash back. Even though the debug logs say it is happening in the correct order which is weird. Its almost as if the script is correct, but rmmz cores are overwriting certain things on its own. It is sideview and Time Progress (Active) if that matters.

/*:
 * @target MZ
 * @plugindesc Moves actor close to enemy when attacking, then attacks. (No return movement yet)
 * @ScarredInteractive
 * @help
 * This plugin modifies attack behavior so that:
 *  1. The actor moves directly to the enemy.
 *  2. The actor stops before attacking.
 *  3. The attack animation plays at the correct time.
 *
 * Debugging logs will appear in the console (F12 in playtest).
 */

(() => {
    const _Game_Battler_performActionStart = Game_Battler.prototype.performActionStart;
    const _Game_Battler_performActionEnd = Game_Battler.prototype.performActionEnd;
    const _Game_Action_apply = Game_Action.prototype.apply;

    // **Intercept step-forward behavior**
    Game_Battler.prototype.performActionStart = function (action) {
        if (this.isActor() && action?.isAttack()) {
            console.log("Blocking default step-forward before attack.");
            return; // Prevent RPG Maker from stepping forward automatically
        }
        _Game_Battler_performActionStart.call(this, action);
    };

    // **Intercept attack execution and force movement first**
    Game_Action.prototype.apply = function (target) {
        const subject = this.subject();
        if (subject.isActor() && target.isEnemy()) {
            console.log(`--- ATTACK SEQUENCE INITIATED ---`);

            // **Stop default attack animation from playing too soon**
            subject._delayedAttack = this; // Store the attack for later execution
            subject.requestMotion("wait");

            moveToEnemy(subject, target, () => {
                console.log(`Actor reached enemy. Now attacking...`);

                // **Now we manually trigger the stored attack**
                executeDelayedAttack(subject, target);
            });

        } else {
            _Game_Action_apply.call(this, target);
        }
    };

    // **Override step-back behavior**
    Game_Battler.prototype.performActionEnd = function () {
        if (this.isActor()) {
            console.log("Blocking default step-back after attack.");
            return; // Prevent RPG Maker's auto return movement
        }
        _Game_Battler_performActionEnd.call(this);
    };

    function moveToEnemy(actor, enemy, callback) {
        const spriteActor = SceneManager._scene._spriteset.findActorSprite(actor);
        const spriteEnemy = SceneManager._scene._spriteset.findEnemySprite(enemy);

        if (spriteActor && spriteEnemy) {
            console.log(`Actor Original Position: x=${spriteActor.x}, y=${spriteActor.y}`);
            console.log(`Enemy Position: x=${spriteEnemy.x}, y=${spriteEnemy.y}`);

            actor._originalX = spriteActor.x;
            actor._originalY = spriteActor.y;

            const targetX = spriteEnemy.x - 40;
            const targetY = spriteEnemy.y;

            console.log(`Moving to target: x=${targetX}, y=${targetY}`);

            spriteActor.startMove(targetX - spriteActor.x, targetY - spriteActor.y, 10);

            const movementChecker = setInterval(() => {
                if (Math.abs(spriteActor.x - targetX) < 2 && Math.abs(spriteActor.y - targetY) < 2) {
                    clearInterval(movementChecker);
                    console.log("Movement to enemy completed!");
                    if (callback) callback();
                }
            }, 50);
        } else {
            console.error("Could not find actor or enemy sprite!");
        }
    }

    function executeDelayedAttack(actor, target) {
        if (actor._delayedAttack) {
            console.log(`Executing stored attack!`);

            actor.requestMotion("attack");

            setTimeout(() => {
                _Game_Action_apply.call(actor._delayedAttack, target);
                console.log(`Attack logic applied!`);

                waitForAttackAnimation(actor, () => {
                    console.log("Attack animation finished. Moving back...");
                    returnToStart(actor);
                });

                actor._delayedAttack = null; // Clear stored attack

            }, 200); // Smooth delay before applying attack
        }
    }

    function returnToStart(actor) {
        const spriteActor = SceneManager._scene._spriteset.findActorSprite(actor);
        if (spriteActor) {
            console.log(`Returning Actor to Original Position: x=${actor._originalX}, y=${actor._originalY}`);
            spriteActor.startMove(actor._originalX - spriteActor.x, actor._originalY - spriteActor.y, 10);

            const returnChecker = setInterval(() => {
                if (Math.abs(spriteActor.x - actor._originalX) < 2 && Math.abs(spriteActor.y - actor._originalY) < 2) {
                    clearInterval(returnChecker);
                    console.log("Actor fully returned to original position.");
                    actor.requestMotion("wait");
                }
            }, 50);
        }
    }

    function waitForAttackAnimation(actor, callback) {
        const spriteActor = SceneManager._scene._spriteset.findActorSprite(actor);

        if (spriteActor) {
            console.log("Waiting for attack animation to finish...");
            const animationDuration = 30; // Approximate time for an attack animation (adjust as needed)

            setTimeout(() => {
                console.log("Attack animation completed.");
                callback();
            }, animationDuration * 16); // 16ms per frame
        } else {
            console.error("Could not find actor sprite for attack animation timing!");
            callback();
        }
    }

    Spriteset_Battle.prototype.findActorSprite = function (actor) {
        return this._actorSprites.find(sprite => sprite._battler === actor);
    };

    Spriteset_Battle.prototype.findEnemySprite = function (enemy) {
        return this._enemySprites.find(sprite => sprite._battler === enemy);
    };

})();

Here are the logs indicating its in absolute perfect order, but gameplay is not...

--- ATTACK SEQUENCE INITIATED ---

MoveBattle.js:64 Actor Original Position: x=664, y=376

MoveBattle.js:65 Enemy Position: x=302, y=270

MoveBattle.js:73 Moving to target: x=262, y=270

MoveBattle.js:80 Movement to enemy completed!

MoveBattle.js:39 Actor reached enemy. Now attacking...

MoveBattle.js:91 Executing stored attack!

MoveBattle.js:97 Attack logic applied!

MoveBattle.js:130 Waiting for attack animation to finish...

MoveBattle.js:134 Attack animation completed.

MoveBattle.js:100 Attack animation finished. Moving back...

MoveBattle.js:113 Returning Actor to Original Position: x=664, y=376

MoveBattle.js:119 Actor fully returned to original position.

MoveBattle.js:53 Blocking default step-back after attack.

本文标签: javascriptRPG Maker MZ Move actor to target battleStack Overflow