조회 수 2735 추천 수 1 댓글 6
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

제대로 된 스크립트를 작성하기 위해서

 

RPG MV의 시스템 스크립트 일부를

 

이해할 필요가 있기에 먼저 설명을 좀 하겠습니다.

 

 

 

1. 배틀러가 행동을 시작합니까?

BattleManager.startAction()을 통해 하게 됩니다.

//일반적으로 배틀러의 턴을 실행하는 함수

BattleManager.processTurn = function() {

    var subject = this._subject;

    var action = subject.currentAction();

    if (action) {

        action.prepare();

        if (action.isValid()) {

            this.startAction();

        }

        subject.removeCurrentAction();

    } else {

        subject.onAllActionsEnd();

        this.refreshStatus();

        this._logWindow.displayAutoAffectedStatus(subject);

        this._logWindow.displayCurrentState(subject);

        this._logWindow.displayRegeneration(subject);

        this._subject = this.getNextSubject();

    }

};

//---------------------------------------------------------------------------------

//강제적인 행동에 의한 배틀러의 행동을 실행하는 함수

BattleManager.processForcedAction = function() {

    if (this._actionForcedBattler) {

        this._subject = this._actionForcedBattler;

        this._actionForcedBattler = null;

        this.startAction();

        this._subject.removeCurrentAction();

    }

};

//---------------------------------------------------------------------------------

//배틀러의 실제적인 행동 실행 함수

BattleManager.startAction = function() {

    var subject = this._subject;

    var action = subject.currentAction();

    var targets = action.makeTargets();

    this._phase = 'action';

    this._action = action;

    this._targets = targets;

    subject.useItem(action.item());

    this._action.applyGlobal();

    this.refreshStatus();

    this._logWindow.startAction(subject, action, targets);

};

 

 

 

2. 행동하는 배틀러는 누구입니까?

subject = this._subject;

this._subejct 가 가르키는 actor 입니다.

 

this._subject = this.getNextSubject();

BattleManager.getNextSubject = function() {

    for ( ; ; ) {

        var battler = this._actionBattlers.shift();

        if (!battler) {

            return null;

        }

        if (battler.isBattleMember() && battler.isAlive()) {

            return battler;

        }

    }

};

또는

 

this._subject = this._actionForcedBattler;

 

this._actionForcedBattler 에 대한 데이터의 흐름

 

 

1) Game_Interpreter의 강제적 행동 판정

// Force Action

Game_Interpreter.prototype.command339 = function() {

    this.iterateBattler(this._params[0], this._params[1], function(battler) {

        if (!battler.isDeathStateAffected()) {

            battler.forceAction(this._params[2], this._params[3]);

            BattleManager.forceAction(battler);

            this.setWaitMode('action');

        }

    }.bind(this));

    return true;

};

 

 

2) BattleManager의 강제적 행동 설정

BattleManager.forceAction = function(battler) {

    this._actionForcedBattler = battler;

    var index = this._actionBattlers.indexOf(battler);

    if (index >= 0) {

        this._actionBattlers.splice(index, 1);

    }

};

 

 

 

3. 배틀러는 어떤 행동을 하게 됩니까?

action = subejct.currentAction();

subejct.currentAction() 에 설정되어 있는 action 을 하게 됩니다.

Game_Battler.prototype.currentAction = function() {

    return this._actions[0];

};

 

 

 

4. 행동의 대상은 누가 됩니까?

targets = action.makeTargets();

targets 로 지정된 대상들입니다.

Game_Action.prototype.makeTargets = function() {

    var targets = [];

    if (!this._forcing && this.subject().isConfused()) {

        targets = [this.confusionTarget()];

    } else if (this.isForOpponent()) {

        targets = this.targetsForOpponents();

    } else if (this.isForFriend()) {

        targets = this.targetsForFriends();

    }

    return this.repeatTargets(targets);

};


Game_Action.prototype.repeatTargets = function(targets) {

    var repeatedTargets = [];

    var repeats = this.numRepeats();

    for (var i = 0; i < targets.length; i++) {

        var target = targets[i];

        if (target) {

            for (var j = 0; j < repeats; j++) {

                repeatedTargets.push(target);

            }

        }

    }

    return repeatedTargets;

};

 

4-1. 행동의 대상을 결정하는 함수들

Game_Action.prototype.confusionTarget = function() {

    switch (this.subject().confusionLevel()) {

    case 1:

        return this.opponentsUnit().randomTarget();

    case 2:

        if (Math.randomInt(2) === 0) {

            return this.opponentsUnit().randomTarget();

        }

        return this.friendsUnit().randomTarget();

    default:

        return this.friendsUnit().randomTarget();

    }

};


Game_Action.prototype.targetsForOpponents = function() {

    var targets = [];

    var unit = this.opponentsUnit();

    if (this.isForRandom()) {

        for (var i = 0; i < this.numTargets(); i++) {

            targets.push(unit.randomTarget());

        }

    } else if (this.isForOne()) {

        if (this._targetIndex < 0) {

            targets.push(unit.randomTarget());

        } else {

            targets.push(unit.smoothTarget(this._targetIndex));

        }

    } else {

        targets = unit.aliveMembers();

    }

    return targets;

};


Game_Action.prototype.targetsForFriends = function() {

    var targets = [];

    var unit = this.friendsUnit();

    if (this.isForUser()) {

        return [this.subject()];

    } else if (this.isForDeadFriend()) {

        if (this.isForOne()) {

            targets.push(unit.smoothDeadTarget(this._targetIndex));

        } else {

            targets = unit.deadMembers();

        }

    } else if (this.isForOne()) {

        if (this._targetIndex < 0) {

            targets.push(unit.randomTarget());

        } else {

            targets.push(unit.smoothTarget(this._targetIndex));

        }

    } else {

        targets = unit.aliveMembers();

    }

    return targets;

};

 

[ 생략 - BattleManager에 _phase / _action / _targets 데이터 지정해주기 ]

 

 

 

5. 배틀러가 아이템을 사용합니까?

: subject.useItem(action.item());

action.item()을 통해 알려주는 아이템을 사용합니다.

Game_Battler.prototype.useItem = function(item) {

    if (DataManager.isSkill(item)) {

        this.paySkillCost(item);

    } else if (DataManager.isItem(item)) {

        this.consumeItem(item);

    }

};

 

 

 

6. 사용한 아이템의 효과를 적용해줍니다.

Game_Action.prototype.applyGlobal = function() {

    this.item().effects.forEach(function(effect) {

        if (effect.code === Game_Action.EFFECT_COMMON_EVENT) {

            $gameTemp.reserveCommonEvent(effect.dataId);

        }

    }, this);

};

 

 

7. BattleManager._phase 에 따른 실행 함수모음

 

실제로 상황에 따른 행동을 실행하는 로직들입니다.

//Scene_Battle부분은 배틀러의 행동을
//결정하는 행동선택 메뉴가 나오는 부분입니다.

//Scene_Battle을 통해서 행동을 결정하기에
//간략하게 넣었습니다.

//어느 곳에서부터 온 코드들인지는
//직접 찾아보시는 것이 도움이됩니다.


Scene_Battle.prototype.updateBattleProcess = function() {

    if (!this.isAnyInputWindowActive() || BattleManager.isAborting() ||

            BattleManager.isBattleEnd()) {

        BattleManager.update();

        this.changeInputWindow();

    }

};


BattleManager.update = function() {

    if (!this.isBusy() && !this.updateEvent()) {

        switch (this._phase) {

            case 'start':

                this.startInput();

            break;

            case 'turn':

                this.updateTurn();

            break;

            case 'action':

                this.updateAction();

            break;

            case 'turnEnd':

                this.updateTurnEnd();

            break;

            case 'battleEnd':

                this.updateBattleEnd();

            break;

        }

    }
};


BattleManager.updateAction = function() {

    var target = this._targets.shift();

    if (target) {

        this.invokeAction(this._subject, target);

    } else {

        this.endAction();

    }

};


BattleManager.endAction = function() {

    this._logWindow.endAction(this._subject);

    this._phase = 'turn';

};


//------------------------------------------------------------------------


BattleManager.invokeAction = function(subject, target) {

    this._logWindow.push('pushBaseLine');

    if (Math.random() < this._action.itemCnt(target)) {

        this.invokeCounterAttack(subject, target);

    } else if (Math.random() < this._action.itemMrf(target)) {

        this.invokeMagicReflection(subject, target);

    } else {

        this.invokeNormalAction(subject, target);

    }

    subject.setLastTarget(target);

    this._logWindow.push('popBaseLine');

    this.refreshStatus();

};


BattleManager.invokeNormalAction = function(subject, target) {

    var realTarget = this.applySubstitute(target);

    this._action.apply(realTarget);

    this._logWindow.displayActionResults(subject, realTarget);

};


BattleManager.invokeCounterAttack = function(subject, target) {

    var action = new Game_Action(target);

    action.setAttack();

    action.apply(subject);

    this._logWindow.displayCounter(target);

    this._logWindow.displayActionResults(subject, subject);

};


BattleManager.invokeMagicReflection = function(subject, target) {

    this._logWindow.displayReflection(target);

    this._action.apply(subject);

    this._logWindow.displayActionResults(subject, subject);

};


Game_Action.prototype.apply = function(target) {

    var result = target.result();

    this.subject().clearResult();

    result.clear();

    result.used = this.testApply(target);

    result.missed = (result.used && Math.random() >= this.itemHit(target));

    result.evaded = (!result.missed && Math.random() < this.itemEva(target));

    result.physical = this.isPhysical();

    result.drain = this.isDrain();

    if (result.isHit()) {

        if (this.item().damage.type > 0) {

            result.critical = (Math.random() < this.itemCri(target));

            var value = this.makeDamageValue(target, result.critical);

            this.executeDamage(target, value);

        }

        this.item().effects.forEach(function(effect) {

            this.applyItemEffect(target, effect);

        }, this);

        this.applyItemUserEffect(target);

    }

};

 

 

 

결론적으로 정리해드리자면...

 

target 은 행동의 대상이 되는 actor이고

 

subject는 행동의 주체가 되는 actor라는 것입니다.

 

 

질문에 들어간 다음의 스크립트에서

 

 

$gameActors.actor(7).mat *35.8 - $gameTroop.members()[0].mdf * 2

 

 

다음의 변수를 공격의 주체인

 

subject 변수가 가르키게 됩니다.

 

$gameActors.actor(7)

 

 

다음의 변수를 공격의 대상인

 

target 변수가 가르기케 됩니다.

 

$gameTroop.members()[0]

 

 

 

공격의 대상인 $gameTroop.members()[0]

 

결과적으로 크리티컬 상태가 true인지

 

조건문으로 체크해주시면 되겠습니다.

 

 

//actor 의 데이터를 세팅하는 함수들

Game_Actor.prototype.initialize = function(actorId) {

    Game_Battler.prototype.initialize.call(this);

    this.setup(actorId);

};

Game_Actor.prototype.initMembers = function() {

    Game_Battler.prototype.initMembers.call(this);

    this._actorId = 0;

    this._name = '';

    this._nickname = '';

    this._classId = 0;

    this._level = 0;

    this._characterName = '';

    this._characterIndex = 0;

    this._faceName = '';

    this._faceIndex = 0;

    this._battlerName = '';

    this._exp = {};

    this._skills = [];

    this._equips = [];

    this._actionInputIndex = 0;

    this._lastMenuSkill = new Game_Item();

    this._lastBattleSkill  = new Game_Item();

    this._lastCommandSymbol = '';

};

Game_Actor.prototype.setup = function(actorId) {

    var actor = $dataActors[actorId];

    this._actorId = actorId;

    this._name = actor.name;

    this._nickname = actor.nickname;

    this._profile = actor.profile;

    this._classId = actor.classId;

    this._level = actor.initialLevel;

    this.initImages();

    this.initExp();

    this.initSkills();

    this.initEquips(actor.equips);

    this.clearParamPlus();

    this.recoverAll();

};

//._actorId는 전역변수 $dataActors에 있는 actor 데이터에
//접근하는데 쓸 수 있고, 액터간의 키 데이터가 됩니다.

//1. 현재 행동의 주체가 되는 actor의 ._actorId 와
//행동의 대상이 되는 actor의 _actorId를 사용하여
//데이터의 일치성을 검사해주시면 됩니다.

//2. 행동의 대상이 되는 actor의 .result().critical 의
//boolean값이 true인가 false인가를 체크해주시면 됩니다.

//3. 연산자는 모든 조건이 만족되어야지만 실행을 해야하기에
//&& 연산자로 모두 묶어주셔야 합니다.


BattleManager.set_target = function (actor){
    BattleManager._target = actor;
};

function find_target_actorId(actor){
    return BattleManager._target._actorId === actor._actorId;
};

//---------------------------------------------------------------------------------

var subject = $gameActors.actor(7);
var target;

BattleManager.set_target($gameTroop.members()[0]);
target = BattleManager._targets.find(find_target_actorId);

if(BattleManager._subject._actorId === subject._actorId
&& typeof target === "object"
&& target.result().critical){
    //데미지 처리는 알아서 하실 수 있을 것이라 봅니다.
}

 

 

결과부분의 2개 함수추가는 하지 않으시면

 

제대로 데이터를 걸러 낼 수 없습니다.

 

 

하나는 BattleManager에서 전역변수화해서

 

BattleManager._target 으로 접근할 수 있도록 합니다.

 

 

다른 하나는 BattleManager._targets 배열 변수에 있는

 

actor 데이터에서 ._actorId 가 BattleManager._target._actorId와

 

같으면 해당 actor의 데이터를 target변수가 가르키게 하는 용도입니다.

 

 

 

 

ps. 혹시나 해보시고 제대로 안되시는 부분이

 

있다면 과감히 질문해주시기 바랍니다.

 

실제 게임을 실행하면서 스크립팅을 한 것이

 

아니라 RPG MV 시스템 스크립트를 뜯어보면서

 

작성한 것이라 실제 실행시에 문제가

 

있을 수 있으니 참고하시기 바랍니다.

?
  • ?
    케에데 2017.01.31 20:46 Files첨부 (1)

    TypeError
    Cannot read property 'list' of undefined 라고 오류가 뜨네요.

    그리고...

    123.jpg

    스크립트 적는 칸이 저렇게 작아서 한줄로 적어야 되는데 처리상의 문제는 없는건가요?

     

  • profile
    lklslel 2017.01.31 22:46

    저는 메뉴얼로 파일에 작성하여 적용하는 타입으로 작성해드렸습니다.

    추가되는 2개의 함수는 플러그인의 형식으로 적용해주시지 않으면

    제대로 작동하지 않거나 참조할 때에 변수에서부터 에러가 납니다.


    그 이유는 케에데님께서 붙여넣으신 에러에서부터 찾아볼 수 있습니다.

    TypeError
    Cannot read property 'list' of undefined

    이 에러의 뜻은

    정의되지 않은 변수(un-defined variable)의 'list' 속서을 읽을 수 없습니다.

    입니다.


    아 오타가 중간에 났습니다.



    var subject = $gameActors.actor(7);
    var target;

    BattleManager.set_target($gameTroop.members()[0]);
    target = BattleManager._target.find(find_target_actorId);

    if(BattleManager._subject._actorId === subject._actorId
    && typeof target === "object"
    && target.result().critical){
    //데미지 처리는 알아서 하실 수 있을 것이라 봅니다.
    }

    부분에서


    target = BattleManager._target.find(find_target_actorId);

    부분을 다음과 같이 수정했습니다.

    target = BattleManager._targets.find(find_target_actorId);

     

     

    제가 제대로 살펴보지 않았습니다.

     

    죄송합니다. 's' 한 글자 오타때문에

     

    Array.find() 함수의 실행부분에서 오류가 났습니다.

  • ?
    마니아 2017.01.31 20:48
    스크립트는 별도의 스크립트 에디터를 실행해서 수정해야...........
  • ?
    케에데 2017.01.31 21:05
    그럼 저렇게 바로 변수에다가는 스크립트를 못쓰는건가요?
    그리고 스크립트 에디터가 MV 자체에 별도로 존재하는 기능인가요? VX나 VXA 때하고는 달리 스크립트 에디터는없고 플러그인 불러오는 기능밖에 없는거 같던데...
  • profile
    lklslel 2017.01.31 22:52
    해당 에러는 변수형 에러입니다.


    Array 형의 데이터가 아닌데 Array 형의 데이터에서만

    사용할 수 있는 .find()함수를 사용했기에 발생한 에러입니다.

    실제로 게임을 실행하면서 테스트를 했다면 에러가 없는

    스크립트를 제공해드릴 수 있었을 텐데 말이죠...
  • profile
    러닝은빛 2017.02.01 13:26

    Yanfly님이 만든 배틀 플러그인들은 데이터베이스의 메모(note)란에 관련 스크립트를 작성할 수 있게 되어있습니다. 예를 들면, 데미지 코어로는 데미지 값을 변경할 수 있습니다. 물론 이런 루나틱 모드를 사용하려면 자바스크립트를 할 줄 알아야 합니다.

     

    <damage formula>
    if (b.result().critical) {
      value = (a.mat *35.8 - b.mdf * 2)* 2;
    } else {
      value = a.mat *35.8 - b.mdf * 2;
    }
    </damage formula>


List of Articles
번호 제목 글쓴이 날짜 조회 수
8668 필요한 스크립트가 있습니다. 4 레스 2014.06.05 387
8667 필력이란 거, 어떻게 키우는 걸까요? 슈크림소녀 2005.06.26 306
8666 필력이란 거, 어떻게 키우는 걸까요? 다르칸 2005.06.26 358
8665 필력이란 거, 어떻게 키우는 걸까요? 세이니 2005.06.26 631
8664 필력이란 거, 어떻게 키우는 걸까요? kalay 2005.07.01 665
8663 필드에서사냥하는법에대해서 알려주세요 막대사탕plus 2006.09.26 366
8662 필드에서... KBOY∮ 2005.06.13 163
8661 필드에서... 늑대소년 2005.06.13 234
8660 필드에서... 뱀신의신교 2005.07.19 169
8659 필드에서 이벤트로 파티원을 얻을때 KBOY∮ 2005.06.08 203
8658 필드에서 이벤트로 파티원을 얻을때 카드모 2005.06.09 245
8657 필드상에서. 필기도구 2005.11.13 284
8656 필드상에서. file 크로스바게트 2005.11.14 441
8655 필독 사항 &꼭 지켜야 하는것들은 어디서 볼수있죠? 2 오리지널아히 2014.10.29 395
8654 픽쳐표시로인한 렉 줄이는 방법.... 無正死人 2006.02.27 309
8653 픽쳐에 대하여 질문합니다 file 로안 2007.01.05 381
8652 픽쳐메뉴에서 반복금지 쿠로군 2007.02.28 137
8651 픽쳐메뉴에서 반복금지 file 글라시아 2007.02.28 355
8650 픽쳐메뉴에 대해서 쿠로군 2007.02.28 137
8649 픽쳐메뉴에 대해서 『덩키동크』 2007.02.28 131
Board Pagination Prev 1 ... 4 5 6 7 8 9 10 11 12 13 ... 442 Next
/ 442






[개인정보취급방침] | [이용약관] | [제휴문의] | [후원창구] | [인디사이드연혁]

Copyright © 1999 - 2016 INdiSide.com/(주)씨엘쓰리디 All Rights Reserved.
인디사이드 운영자 : 천무(이지선) | kernys(김원배) | 사신지(김병국)