조회 수 2738 추천 수 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 2003)주인공 걸음속도 조절 다크세이버™ 2006.09.03 215
8667 2003)주인공 걸음속도 조절 정석 2006.09.05 226
8666 2003-이름입력의 처리 질문입니다 Zeprod 2007.01.11 286
8665 2003-이름입력의 처리 질문입니다 file 새벽도둑 2007.01.11 404
8664 2003]초보적 질문하나올립니다 소랑군 2005.10.23 119
8663 2003]초보적 질문하나올립니다 잃어버린98 2005.10.20 205
8662 2003관련 질문입니다. 새벽도둑 2007.01.08 369
8661 2003기본전투 이벤트에 대한 질문. 『덩키동크』 2007.11.02 244
8660 2003기본전투 이벤트에 대한 질문. 풍자 2007.11.02 566
8659 2003기본전투에 대해 질문있습니다 이상무 2007.01.16 394
8658 2003문장 영어 『덩키동크』 2005.12.27 282
8657 2003쓰는데요..공격할때.. 내마음블루 2005.06.06 146
8656 2003쓰는데요..공격할때.. 아크로드 2005.06.06 232
8655 2003에서 "칸" 형 게이지 만들기 질문. 『덩키동크』 2007.08.07 337
8654 2003에서 "칸" 형 게이지 만들기 질문. Lathanter 2007.08.07 816
8653 2003에서 그림표시와 전투애니질문 다크아머 2006.01.22 261
8652 2003에서 그림표시와 전투애니질문 아르킨 2006.01.22 313
8651 2003에서 쓰던 칩셋들을 xp에서 사용가능한가요? 검둥괭이 2006.01.08 251
8650 2003에서 전투에니메이션용 그림들 질문요 찰드 2010.06.17 1114
8649 2003에서 전투에니메이션용 그림들 질문요 1 jangbora 2010.07.02 1007
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(김원배) | 사신지(김병국)