조회 수 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>


  1. 쯔꾸르 VX Ace 게임 오류 Alert!

    Date2017.02.02 By가세공세 Views6904
    Read More
  2. alert라면서 게임이실행되지않아요

    Date2017.02.01 Byboru3990 Views932
    Read More
  3. 인디사이드로 네코플레이어(모바일) 게임 만들때 캐쉬 시스템은 있나요?

    Date2017.02.01 By신호등 Views725
    Read More
  4. 케에데님께서 원하시는 설명 - 스압주의 -

    Date2017.01.31 Bylklslel Views2735
    Read More
  5. 파일 바로 뒤에 exe 파일을 넣었는데 실행기가 안보입니다.

    Date2017.01.25 By암통곡 Views461
    Read More
  6. 이게 정확히 무슨 오류죠?

    Date2017.01.25 ByDuranDuran Views730
    Read More
  7. 스크립트관련 질문입니다.

    Date2017.01.24 By엽여비소엽 Views372
    Read More
  8. RPG MV 자바 스크립트 잘아시는분 질문드려봐요.

    Date2017.01.23 By케에데 Views1212
    Read More
  9. [사진첨부]RPG MAKER MV의 자원관리의 가져오기 버튼을 눌렀더니 도트그림이 사라졌어요.

    Date2017.01.22 By고물떡 Views541
    Read More
  10. rpg vx ace 강좌 질문 기초적인것 여러가지

    Date2017.01.20 By아래아 Views444
    Read More
  11. 네코rpg xp 쯔꾸르게임 버전업후 오류

    Date2017.01.19 By캣킷 Views3024
    Read More
  12. 설치안된게잇고설치된건없네요..

    Date2017.01.19 By초코뺭 Views265
    Read More
  13. 게임 파일 올리고 나서

    Date2017.01.14 By드래곤규 Views253
    Read More
  14. apk서비스이용관련)유료게임판매시 수익배분이 어떻게되는지알고싶습니다.

    Date2017.01.11 By창문깬산타 Views854
    Read More
  15. 이벤트를 움직이게 하고 맵을 나갔다오면 제자리에 돌아가있습니다.

    Date2017.01.09 By뀨뀨까까 Views729
    Read More
  16. 스크립트로 갤러리 해금 어떻게 하나요?

    Date2017.01.07 Byc22sue Views399
    Read More
  17. [MV] 캐릭터의 기본 보행속도를 줄이려면 어떻게 하나요?

    Date2017.01.06 By흰자 Views2347
    Read More
  18. 아오오니 파일 질문

    Date2017.01.06 ByLimes Views435
    Read More
  19. 긂긂 그림

    Date2017.01.06 By새준 Views313
    Read More
  20. 메뉴질문

    Date2017.01.06 By새준 Views335
    Read More
Board Pagination Prev 1 ... 6 7 8 9 10 11 12 13 14 15 ... 442 Next
/ 442






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

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