【解決】マップ上でのターン制を実装したい

おのき
記事: 14
登録日時: 2017年8月28日(月) 18:07
連絡を取る:

【解決】マップ上でのターン制を実装したい

投稿記事by おのき » 2017年9月02日(土) 18:56

お邪魔します。

今回,マップ上でプレイヤーが1回行動したら敵も行動するというターン制を実装したいです。
そこでNPCの移動処理(update?)が行われている場所を知りたいです。
入力待ちフラグは別途用意したほうがいいでしょうね。

たびたび初歩的な質問で申し訳ありません。
まずはゲームとして成立する最低限のラインを目指していきたいです。
どうかお力をお貸し頂ければ幸いです。

【今回のチラシ裏】
JavaScriptの悪い部分ばかりに目が行き,TypeScriptに移行しようかと本分を見失いそうになっています。
自分の悪いクセだと自覚しております。
まだJavaScriptを知りもしないのに。
最後に編集したユーザー おのき on 2017年9月03日(日) 18:36 [ 編集 1 回目 ]

アバター
しぐれん
記事: 682
登録日時: 2017年3月28日(火) 22:22
連絡を取る:

Re: マップ上でのターン制を実装したい

投稿記事by しぐれん » 2017年9月02日(土) 19:19

Game_Character.update周辺を探せば出てきます。
あるいは、Scene_Map.update周辺。

【余談】
ツクールMVのデータはMVCパターンに基づいて構築されています。
M(model) :rpg_objects.js
V(view) :rpg_windows.jsまたはrpg_sprites.js
C(control):rpg_scenes.js

この場合、rpg_objectsを調べれば出てきます。
探し物の参考になれば。

ツクールMVではES2015以降のクラス構文が一応動くので、それを使うのも手です。
入力補完なら、RPGmalerIntellisenseを導入すれば割と何とか。
TypeScriptに移行したくなるのはわからなくもないですが、似たようなことをやって私も昔に死にました。
有償でプラグイン作成リクエストに対応しています。
ご興味のある方は、こちらのリンクからどうぞ。
ツクールMV・プラグイン作成依頼受付
おのき
記事: 14
登録日時: 2017年8月28日(月) 18:07
連絡を取る:

Re: マップ上でのターン制を実装したい

投稿記事by おのき » 2017年9月03日(日) 16:40

>しぐれん様
ありがとうございます。
教えていただいた情報で考えてみます。

【余談】
色々おいしい話を教えていただき感謝です。
特にES2015とかRPGmalerIntellisenseは目から鱗でした。
早速導入しました。

↓『RPGmalerIntellisense』
https://goo.gl/CNzQ6S
おのき
記事: 14
登録日時: 2017年8月28日(月) 18:07
連絡を取る:

Re: マップ上でのターン制を実装したい

投稿記事by おのき » 2017年9月03日(日) 18:35

ターン制について私なりの考えをまとめてみます。

各キャラの行動に重みを付けてみたらどうでしょうか?

前提として,重み変数(moveWeight)が0で入力待ち状態とします。
例えばプレイヤーが移動したとしてmoveWeightは1になります。
これはプレイヤーが1ターン分行動したことを示します。
よって各NPCはmoveWeightの1相当だけ行動できます。
実装では,moveWeightが1以上になっていればNPCのターンです。
各NPCは自分の行動重量分をmoveWeightから取り除いていきます。

プレイヤーが倍速だったらmoveWeightに0.5を足せばいいです。
moveWeightが1以上になった時点でNPCのターンですね。
逆に遅ければmoveWeightに2を足すことで,各NPCはmoveWeightが0になるまで行動できます。

こんな感じでしょうか。
お仕事の時間なので実装は後日ですね。
ありがとうございました。

【追記】
上記はあくまで理想論でしたね。
ところどころ間違っていますし・・。
現実的な実装はあと少しで完成しそうです。
完成したら投稿します。
おのき
記事: 14
登録日時: 2017年8月28日(月) 18:07
連絡を取る:

Re: 【解決】マップ上でのターン制を実装したい

投稿記事by おのき » 2017年9月09日(土) 05:15

訂正します。
上記のmoveWeight理論は拡大解釈すれば実現可能です。

【ターン制システムの概要】
Game_PlayerとGame_Eventの基本クラスGame_CharacterにmoveWeightを持たせます。
キャラ固有の消費moveWeightをbaseWeightとします。
通常速度のbaseWeightを(計算の都合がいいので)仮に6とします。
ターン開始時,各キャラのmoveWeightにプレイヤーのbaseWeightを加えます。
(※1ターンの速度をプレイヤー基準とする場合)
1つ行動するたびにmoveWeightからbaseWeight分を取り除きます。
例えばプレイヤーのbaseWeightが3だとすれば,通常速度の6では足りないため1ターン行動不能になります。
先行はプレイヤーで,各NPCの行動が終われば次のターンです。

実装全体を公開するとネタバレになるので一部を載せておきます。
どうぞお使いください。

コード: 全て選択

(function() {
  'use strict';// 厳格モード

  /////////////////////////////////////////////////////////////////////////////
  //Scene_Map
  Scene_Map.prototype.updateMain = function() {
    var active = this.isActive();
    $gameMap.checkNextTurn();// ターン進行チェック
    $gameMap.update(active);
    $gamePlayer.update(active);
    $gameTimer.update(active);
    $gameScreen.update();
  };

  /////////////////////////////////////////////////////////////////////////////
  // Game_Map
  var _Game_Map_setup = Game_Map.prototype.setup;
  Game_Map.prototype.setup = function(mapId) {
    _Game_Map_setup.apply(this, arguments);
    this._turn = -1;// 現マップでの経過ターン
    $gamePlayer._stepAnime = true;// 常に足踏み
    $gamePlayer.setMoveSpeed(4);
  };

  Game_Map.prototype.checkNextTurn = function() {
    if ($gamePlayer.isRestMover()) {
      return;
    }
    for (var i = 1; i < this._events.length; ++i) {
      if (this._events[i].isRestMover()) {
        return;
      }
    }
    for (var i = 1; i < this._events.length; ++i) {
      //$gameMessage.add('ハロー');
      this._events[i].addMoveWeight();
    }
    $gamePlayer.addMoveWeight();
    ++this._turn;
  };

  /////////////////////////////////////////////////////////////////////////////
  // Game_Character
  var _Game_Character_initMembers = Game_Character.prototype.initMembers;
  Game_Character.prototype.initMembers = function() {
    _Game_Character_initMembers.apply(this, arguments);
    this._moveWeight = 0;// 行動量
  };

  var _Game_Character_setMovementSuccess = Game_Character.prototype.setMovementSuccess;
  Game_Character.prototype.setMovementSuccess = function(success) {
    _Game_Character_setMovementSuccess.apply(this, arguments);
    if (this.isMovementSucceeded()) {
      this.removeWeight();
    }
  };

  Game_Character.prototype.getBaseWeight = function() {
    switch (this._moveSpeed) {
      case 1: return 0;// 停止
      case 2: return 18;// 1/3倍速
      case 3: return 12;// 1/2倍速
      case 4: return 6;// 通常
      case 5: return 3;// 2倍速
      case 6: return 2;// 3倍速
      default: throw new Error('The getBaseWeight() value is invalid');
    }
  };

  Game_Character.prototype.addMoveWeight = function() {
    this._moveWeight += $gamePlayer.getBaseWeight() || 6;
  };

  Game_Character.prototype.removeWeight = function() {
    this._moveWeight -= this.getBaseWeight() || this._moveWeight;
  };

  Game_Character.prototype.isRestMover = function() {
    if (this.getBaseWeight() <= 0) {
      return false;
    }
    return this._moveWeight >= this.getBaseWeight();
  };

  /////////////////////////////////////////////////////////////////////////////
  // Game_Event
  Game_Event.prototype.updateSelfMovement = function() {
    if ($gamePlayer.isRestMover() || !this.isRestMover()) {
      return;
    }
    if (!this._locked && this.isNearTheScreen() &&
        this.checkStop(this.stopCountThreshold())) {
      switch (this._moveType) {
        case 1:
        this.moveTypeRandom();
        break;
        case 2:
        this.moveTypeTowardPlayer();
        break;
        case 3:
        this.moveTypeCustom();
        break;
      }
    }
  };

  /////////////////////////////////////////////////////////////////////////////
  // Game_Player
  // マル秘
})();
青猫_
記事: 42
登録日時: 2017年11月07日(火) 22:47

Re: 【解決】マップ上でのターン制を実装したい

投稿記事by 青猫_ » 2017年11月07日(火) 23:27

はじめまして、解決済みのトピックに失礼します。
ローグライクRPG風のターン制マップ移動のスクリプトを探して、ここに辿りつきました。
コードを参考にさせていただきます。

図々しいお願いですが、トピックのトップでおっしゃっていた「別途用意した入力待ちフラグ」についても、教えていただけないでしょうか?
プレイヤーの行動が完了後、同エリア内の全てのイベント(敵のシンボル)が行動を完了し、
初めてプレイヤーにターンが回ってくるフラグの事だと思いますが・・・・・・
おのき
記事: 14
登録日時: 2017年8月28日(月) 18:07
連絡を取る:

Re: 【解決】マップ上でのターン制を実装したい

投稿記事by おのき » 2017年11月08日(水) 00:29

>青猫_様

こんにちは。
ずいぶん前に書いたことなのでうろ覚えですが。
「入力待ちフラグ」というのは、例えばの話だと思います。
気にしないでください。
ターン制については後述の行動量の考えを利用すれば実装できます。
プレイヤーの入力処理の部分で、皆が行動終了しているかを判定すればいいです。
これが入力待ちフラグのことです。

ただいまコードが手元にないので詳しくはお話しできません。
よくわからなければご連絡下さい。
コードの一部くらいはお見せできると思います。
青猫_
記事: 42
登録日時: 2017年11月07日(火) 22:47

Re: 【解決】マップ上でのターン制を実装したい

投稿記事by 青猫_ » 2017年11月08日(水) 11:55

早速のお返事ありがとうございます。
となると、私の導入方法が悪いのか、
キャラクターを一歩動かすごとに、イベントも一歩近づいてきて、接触すると戦闘、というイベントを作りたかったのですが、
頂いたコードをjsファイルに出力→pluginsフォルダに入れてプラグイン管理画面からonに、
イベントの実行内容にも同じスクリプトを入力し、自律移動を「近づく」に設定すると、
プレイヤーの行動量に応じてイベントも動いているのは間違いないのですが、
ターン制の入力待ちが適応されておらず、プレイヤーが自由に移動できると同時に、
イベントも標準速で一歩一歩歩きだし、プレイヤーが移動した分移動すると停止するような状態になってしまいました。

何か初歩的なミスを犯している気がするのですが、よろしければご教示いただけたらと思います。
おのき
記事: 14
登録日時: 2017年8月28日(月) 18:07
連絡を取る:

Re: 【解決】マップ上でのターン制を実装したい

投稿記事by おのき » 2017年11月08日(水) 18:02

>青猫_様

すいません。
上記のコードはプラグインとして導入することを想定していないです。
そのため,ご期待に沿えない可能性がございます。

ひとつだけ確認させてください。
イベントの頻度の設定は「最高」にされてますでしょうか。

もし設定が煩わしければ,該当部分を下記に修正することで「頻度」を無効にできます。

コード: 全て選択

  /////////////////////////////////////////////////////////////////////////////
  // Game_Event
  Game_Event.prototype.updateSelfMovement = function() {
    if ($gamePlayer.isRestMover() || !this.isRestMover()) {
      return;
    }
    if (!this._locked && this.isNearTheScreen()) {
      switch (this._moveType) {
        case 1:
        this.moveTypeRandom();
        break;
        case 2:
        this.moveTypeTowardPlayer();
        break;
        case 3:
        this.moveTypeCustom();
        break;
      }
    }
  };

以下,お断り書きです。

プラグインとして公開するつもりはないので動作保証外です。
予期せぬ不具合があるかもしれません。
ご了承お願いします。

【追記】
さらなるご指摘ありがとうございます。
帰ってから返信します。
最後に編集したユーザー おのき on 2017年11月08日(水) 22:04 [ 編集 1 回目 ]
青猫_
記事: 42
登録日時: 2017年11月07日(火) 22:47

Re: 【解決】マップ上でのターン制を実装したい

投稿記事by 青猫_ » 2017年11月08日(水) 21:11

>おのき様

頻度を「最高」にした所、プレイヤーの行動速度と同じ頻度で行動を取るようになったため、
目標に非常に近い挙動を取ってくれるようになりました!
ありがとうございます。
ダッシュするとずれてしまいますが、これは敵が居るエリアのダッシュを禁止すればいいだけなので問題ありません。

たびたびお手数かけて申し訳ありませんが、もう一つ教えていただけませんか?
「足踏み」や「一回休み」のようなコードはどういう物になるのでしょうか?
例えばこの↓ブログの「使用できるキーを増やす」を参考に、
http://blog.livedoor.jp/trb_surasura/ar ... 28522.html
キーボードの「C」を押すと、その場で行動量(moveWeigh)を6増やす「足踏み」や、
メニューからアイテムを使うと1ターン使用し、相手のターンが来るようにしたいのですが……

私の拙い理解力では、おそらく
Game_Character.prototype.addMoveWeight = function() {
this._moveWeight += $gamePlayer.getBaseWeight() || 6;
あたりが関係しているのでは?程度しか到達できず、すみません。

“MV:質問” へ戻る