조회 수 2733 추천 수 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
번호 제목 글쓴이 날짜 조회 수
8628 쯔꾸르 VX Ace 게임 오류 Alert! 1 가세공세 2017.02.02 6899
8627 alert라면서 게임이실행되지않아요 1 boru3990 2017.02.01 932
8626 인디사이드로 네코플레이어(모바일) 게임 만들때 캐쉬 시스템은 있나요? 2 file 신호등 2017.02.01 725
» 케에데님께서 원하시는 설명 - 스압주의 - 6 lklslel 2017.01.31 2733
8624 파일 바로 뒤에 exe 파일을 넣었는데 실행기가 안보입니다. file 암통곡 2017.01.25 461
8623 이게 정확히 무슨 오류죠? 1 file DuranDuran 2017.01.25 730
8622 스크립트관련 질문입니다. 엽여비소엽 2017.01.24 372
8621 RPG MV 자바 스크립트 잘아시는분 질문드려봐요. 4 케에데 2017.01.23 1212
8620 [사진첨부]RPG MAKER MV의 자원관리의 가져오기 버튼을 눌렀더니 도트그림이 사라졌어요. 고물떡 2017.01.22 538
8619 rpg vx ace 강좌 질문 기초적인것 여러가지 아래아 2017.01.20 444
8618 네코rpg xp 쯔꾸르게임 버전업후 오류 1 file 캣킷 2017.01.19 3011
8617 설치안된게잇고설치된건없네요.. 초코뺭 2017.01.19 265
8616 게임 파일 올리고 나서 드래곤규 2017.01.14 253
8615 apk서비스이용관련)유료게임판매시 수익배분이 어떻게되는지알고싶습니다. 5 file 창문깬산타 2017.01.11 854
8614 이벤트를 움직이게 하고 맵을 나갔다오면 제자리에 돌아가있습니다. 1 뀨뀨까까 2017.01.09 729
8613 스크립트로 갤러리 해금 어떻게 하나요? c22sue 2017.01.07 398
8612 [MV] 캐릭터의 기본 보행속도를 줄이려면 어떻게 하나요? 2 흰자 2017.01.06 2315
8611 아오오니 파일 질문 Limes 2017.01.06 435
8610 긂긂 그림 새준 2017.01.06 313
8609 메뉴질문 새준 2017.01.06 335
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(김원배) | 사신지(김병국)