ヒキニートがゲームを作るブログ

Unityでゲームを作る過程を投稿します

ユニットに指示を出すー仕様を決める【UnityでRTSを作る 13】

今回の記事は「ランダムマップの生成」になるはずでしたが、
ランダムマップの実装が現時点では記事にできるレベルじゃないので、
内容を変更して「ユニットに指示を出す」の実装をします。

結構長いので記事は複数に分けます。

今回は「ユニットに指示を出す」でぶつかった問題を整理して仕様を決めます。

ぶつかった問題

ユニットへの指示の実装でぶつかった問題をまとめました。

ユニット選択

  • カメラに映っているプレイヤーの周りのユニットしか選択できない。
  • プレイヤーの移動が画面を押し続けることなので、短形選択とかができない。
  • ほとんどの場合、プレイヤーにユニット選択をする時間猶予がない。

どの問題もプレイヤーのオブジェクトが存在することで起きてる制限ですね…
RTSとプレイヤーを同居させるのはかなり大変そうです。

名案!
TimeLockerのような「プレイヤーが動いている間だけ時間を進める」という機能を実装すれば、プレイヤーにユニットを選択する猶予を与えられるのでは?

目標設定

ユニットの選択とほぼ共通した問題があります。
そして何より問題なのが、良い解決策が浮かばない。

実装方法の候補

選択式

指示を出したいユニットをタップして選択する方法です。
ある程度自由が利きますが、複数の指示を出すのが大変です。

ピクミン

プレイヤーから一定の範囲内のユニットを全て選択する方法です。

選択式よりは操作性は上がりますが、
かゆいところに手が届かないという問題があります。

またプレイヤーが移動しながらこれを行う場合、
操作性を損なわない為には何かしらの工夫が必要となります。
(片手だけで移動と選択を同時に行いたい)

目標設定

これに関しては現時点では良いアイデアが浮かびませんでした。

今回はとりあえず「選択したユニットはプレイヤーと同じ目標を狙い続ける」
という形で仮実装しようと思います。

仕様の決定

考えた結果、ユニット選択にはピクミン式」を採用します。
シンプルな操作性で実装したいからです。

具体的な仕様

  • プレイヤーが動いている間だけ時間を進める
  • 選択をしたい場合プレイヤーを長押し
  • 選択をしながら移動する場合はプレイヤーをタップして引っ張るように移動
  • 選択したユニットはプレイヤーと同じ目標を狙い続ける
  • 選択は任意のタイミングで外せる

動いている間だけ時間を進める

今回は「プレイヤーが動いている間だけ時間を進める」だけを実装します。

Player.cs(重要部分を抜粋)

protected override void Update () {
	Mover.canMove = Input.GetMouseButton(0);
	Mover.canSearch = Mover.canMove;
	GameManager.Clock.paused = !Mover.canMove;
	if (Mover.canMove && Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition),out hit)) {
		Pointer.position = hit.point;
		Mover.Move();
		RotateArm();
	}
}

移動ボタンを押していなかったらClockを一時停止させます。

この変更で時間制御ボタンのポーズ処理が要らなくなったのでそれを削除します。

TimeControlButton.cs(重要部分を抜粋)

using Chronos;

private void OnClick () {
	switch (GameManager.TimeState) {
		//case TimeState.Paused: GameManager.Clock.localTimeScale = 1; break;
		case TimeState.Normal: GameManager.Clock.localTimeScale = 2; break;
		case TimeState.Accelerated: GameManager.Clock.localTimeScale = 1; break;
	}
	SetIcon();
}

private void SetIcon () {
	switch (GameManager.TimeState) {
		//case TimeState.Paused: image.sprite = pausedIcon; break;
		case TimeState.Normal: image.sprite = normalIcon; break;
		case TimeState.Accelerated: image.sprite = acceleratedIcon; break;
	}
}

イメージ

ランダムマップ実装はしましたが見ての通りのお粗末な出来です。
そのうちしっかりと実装します。