ポケモンのようなターン制のゲームを開発してまして、そこで上手く実装できた部分の書き方を共有します。続いたり続かなかったり。今回はターン終了時の処理です。
#概要
- ポケモン風ターン制ゲームとは
- ポケモンにおけるターン終了時の処理
- StateMachine (ステートマシン)とは
- Coroutine (コルーチン)とは
- コードサンプル
- 解説
#ポケモン風ターン制ゲームとは
以下の特徴を持ったゲームです
- ターン開始時にお互いがわざ選択を行う
- キャラクターは素早さ順に行動する
- わざはダメージを与えたり、特殊効果を持つ
- キャラクターが先に全滅すると負け
#ポケモンにおけるターン終了時の処理
ざっとこんだけあります
1.天候解除(→ギフト/てんきや)→天候ダメージ/サンパワー/かんそうはだ/あめうけざら/アイスボディ
2.みらいよち/はめつのねがい
3.ねがいごと
4.だっぴ/うるおいボディ/いやしのこころ
→くろいヘドロ/たべのこし/グラスフィールドの回復
5.アクアリング
6.ねをはる
7.やどりぎのたね
8.どく/もうどく/ポイズンヒール
9.やけど
10.あくむ
11.呪い
12.しめつける状態解除
→しめつける/まきつく/うずしお/マグマストーム/すなじごく/ほのおのうず/からではさむ/まとわりつく
13.あくび
14.ほろびのうた
15.ちょうはつ
16.アンコール
17.かなしばり
18.でんじふゆう
19.かいふくふうじ
20.さしおさえ
21.リフレクター
22.ひかりのかべ
23.しんぴのまもり
24.しろいきり
25.おいかぜ
26.おまじない
27.トリックルーム
28.じゅうりょく
29.みずあそび/どろあそび
30.ワンダールーム
31.マジックルーム
32.グラスフィールド/エレキフィールド/ミストフィールド
33.さわぐ
→ナイトメア/しゅうかく/ものひろい/ムラっけ/どくどくだま/かえんだま/くっつきバリ
これらの詳しい効果について知る必要はありません。
重要なのは、各処理は行われる場合と行われない場合があり、処理が行われる場合には、「順番に」エフェクトやUI表示を行う必要があるということです。
#ステートマシンとは
ポケモンのようなターン制ゲームの場合、わざを選択するタイミング、わざを出すタイミング、ターン終了時の処理をするタイミングなど、ゲームの状態を見て進行を管理する仕組みが必要です。
そういった仕組みを「ステートマシン」と呼びます。詳しくは割愛するので知らない方は調べてみてください。
#コルーチンとは
簡単に言うと一定時間処理を止められる仕組みです。
今回で言えば、例えば毒状態で毒ダメージを受けている間は処理を止めておき、それが終わったら次は宿り木の種の処理を行う、といった制御が必要です。
そういった制御にピッタリなのがコルーチンで、これを使った実装方法を紹介します。
#コードサンプル
論点でない部分のコードは割愛しています。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TurnStateMachine : MonoBehaviour
{
public Pokemon myPokemon;
public Pokemon enemyPokemon;
List<Pokemon> SortedPokemons = new List<Pokemon> ();
/* ターン終了時の処理に関わる部分以外は割愛 ステートマシンで制御します*/
void StartTurnEndProcessing()
{
//コルーチンを開始
StartCoroutine(TurnEndProcessing());
}
//コルーチン処理
IEnumerator TurnEndProcessing ()
{
//1.勝敗判定
if (CheckAlive()) {
yield break;
}
//2.同速チェックと並び替え
bool isSame = Sort ();
//3.天候解除
if (WeatherProcessing ()) {
yield return new WaitForSeconds (1f);
}
/* 中略 */
//4.素早さが同じ場合は順番をシャッフルする
Shuffle (isSame);
//5.毒ダメージ
foreach (var item in SortedUnits) {
if (PoizonProcessing (item)) {
yield return new WaitForSeconds (0.5f);
}
}
/* 中略 */
//6.勝敗判定
if (CheckAlive()) {
yield break;
}
//7.交代の有無を確認
if(CheckChange()){
//交代の処理
CharacterChange();
} else {
//ターン開始に移る処理
TurnStart();
}
}
bool Sort ()
{
//myPokemonとenemyPokemonの素早さを比較
//素早さが高い順にSortedPokemonsにAddする
//素早さが同じ場合はtrue,それ以外はfalseを返す
}
void Shuffle (bool isSame)
{
//素早さが同じ場合は順番のシャッフルを行う
//素早さが同じでない場合は何もしない
}
bool WeatherProcessing ()
{
//天候解除の有無を判定する
//天候解除ありの場合はエフェクトやUI表示を更新してtrueを返す
//それ以外はfalseを返す
}
bool PoizonProcessing (Pokemon pokemon)
{
//pokemonが瀕死状態ならfalseを返して終了する
//pokemonが毒状態ならエフェクトと毒ダメージの処理を行う
//それ以外はfalseを返す
}
bool CheckAlive()
{
//対戦の勝敗判定を行う
//勝ちまたは負けの判定が出た場合はtrueを返す
//それ以外はfalseを返す
}
bool CheckChange()
{
//交代の有無を判定して交代が必要な場合はtrueを返す
}
void CharacterChange()
{
//ポケモンの交代の必要があれば交代画面に映る
}
void TurnStart()
{
//ターン開始時に移る
}
}
#解説
以下がポイントです。
-
最初に勝敗判定を行って、勝敗が決する場合は処理を行わない//1.参照
-
砂嵐ダメージなどポケモン毎に行う処理は、素早さ順で行われる。
→最初に素早さ順でListに追加しておき、List内の順番に沿って処理する。//2.参照 -
素早さが同じ場合は処理毎に素早さ順の判定を行う。
→素早さが同じ場合だけシャッフル処理を行う。//4.参照 -
エフェクト表示やUI更新が必要な時だけ待機時間を設ける
→個別の処理は処理の有無をbool値で返して、trueの時のみ待機する。//3,5.参照
→コルーチンの待機時間はyield return new WaitForSeconds (float);
で表せます。 -
毒ダメージなどでターン終了時の処理中にポケモンが瀕死になる場合があるため、最後の方で再度勝敗判定を行う。//6.参照
以上、マニアック気味の内容でした。
他のターン状態を管理する処理については割愛しています。
もし参考になった場合はいいねをお願いします。