What's This?

このブログは不定期に更新されるゲーム製作アラカルトのメモ帳です。
記事は以下のカテゴリーに分類されてます。(クリックで記事一覧表示)

全てのソースコードのライセンスについてはこちら

書いてる人→@eiki_okuma

 

SpriteRenderer の裏をぼかすシェーダ

意外と無かったので作りました

 

Shader "Custom/Sprite - BlurBack"
{
    Properties
    {
        [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
        _BlurAmount("Blur Amount", Float) = 0.1
    }

    SubShader
    {
        Tags { "Queue" = "Transparent" }
        GrabPass { "_BGTexture" }    // GrabPass を使用。シンプル!

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            sampler2D _BGTexture;
            float _BlurAmount;

            v2f vert( appdata v )
            {
                v2f o;
                o.vertex = UnityObjectToClipPos( v.vertex );
                o.uv = v.uv;
                return o;
            }

            half4 frag( v2f i ) : SV_Target
            {
                // ガウシアンぼかし
                float4 col = tex2D(_BGTexture, i.uv);
                float2 blurSize = float2(_BlurAmount / _ScreenParams.x, _BlurAmount / _ScreenParams.y);
                for (int x = -1; x <= 1; x++)
                {
                    for (int y = -1; y <= 1; y++) col += tex2D( _BGTexture, i.uv + float2(x, y) * blurSize );
                }
                return col / 9.0f;
            }
            ENDCG
        }

    }
}

GrabPass 便利ですね。(コンソールとかでも問題なく使えるんかな……?)

秒で使えるタイピングゲームのエンジンを作りました

タイピングゲーム制作キット

 日本語のタイピングゲーム作りたいな~と思った時に、ネット上にチラホラ資料は見つかるものの決定版がなかったので自分で作りました。

 アセットストアのコンプリートプロジェクトやスクリプト系アセットって、たしかにデモの画面は再現できるんだけどいざ開いてみると複雑怪奇な構造をしていて、無駄にスクリプトファイルが分断してたりデモに必須機能が埋め込まれていたりして自分のプロジェクトへの導入に手間取ることが結構あるんですよね。

 その点このアセットはシンプルに作りましたので、秒であなたのプロジェクトにタイピングゲーム機能をぶち込めます。(いるか?)

 ファイル構造はこんな感じ。必要なものは Core に入っている二つの .cs だけです。
 問題データは表示する文字+読み仮名の (string,string) を TypingEngine に渡せばOKで、 Demo では Questions.cs に入ってますが、適当に整備すればOKです。(後述する自作ゲームでは Google Spread Sheet からデータを下ろしてきています)

演出面

 タイピングゲームチュートリアルとかだと「とりあえず入力受け取れればOK」みたいな感じで、現在入力中の文字がどこなのか表示されなかったり、柔軟な入力に対応してなかったり、柔軟な入力をした時に例文のローマ字が変化しなかったりと割と不親切な仕上がりになることも多いですが、デモ動画を見ると分かるようにこのアセットではそういったあたりまである程度対応しています。

 文字入力とかもちゃんとフックできるようになっているので、改造次第で割とリッチな演出もいけます。こういうのって大事ですよね。

 

完成ゲーム例

 で、何を隠そうこのエンジンは去年 unity1week で出したタイピングゲームのエンジンをそのまま分離したものなので、そのままこのゲームが応用例になります。

ためてまわす鳥さんタイピング | フリーゲーム投稿サイト unityroom

 

 他にもあらゆるタイピングゲームが作れると思いますが、例えばタイピングオブザデッドのように複数の目標が出てきてどこからでも倒すことができるようなゲームの場合、TypingEngine を複数作るのがコツです。取り回しも大変楽。

*OnGUI をエンジンに入れ込みたかったので MonoBehaviour になっていますが、OnGUI さえ別の場所から呼んでしまえば MonoBehaviour を外すことも可能です。

 

 

 というわけで、雑にタイピングゲーム作りたくなった人はぜひ焼肉定食をぼくにおごってください。よろしくネ!

【Unity】New Input System をバッチリ使う

 Unity の New Input System、使ってますか。

 長らく Unity 製ゲームでまともにゲームパッドキーコンフィグに対応しようとすると Rewired というアセットを使わざるを得なかったんですが、Unity が公式にこれら機能に対応してくれました。ありがとう Unity。ちょっと遅いぞ Unity。

 早速飛びついて一本ゲームを作るまで一応使い込んだので、解説します。

 

二つの使い方

 さて、New Input System のコア部分には二つの使い方があります。

  • ラッパーである PlayerInput を使う方法
  • C# クラスを Generate して、それを new して使う方法

アセット設定

 で、ネットを検索するとどうも前者の情報しか出てこないんですよね。しかし、自分的には PlayerInput を Component でいちいち追加しないといけないのは GameObject の取り回しが面倒なので避けたい。ので、自分は後者の方法でやってます。後者の方法で New Input System を使うには、新規作成した inputactions アセットで Generate C# Class にチェックを入れるだけ。あ、この前段階のパッケージインポート云々は適当なチュートリアルサイト漁ってください。

 この記事ではクラス名は GeneralInput とします。

 

セットアップ例

 アリスではこんな感じ。Gamepad と Keyboard 両対応です。

 

入力を取る

public enum EInputName {/*略*/}
GeneralInput mInput = null;
InputAction[] mActions = new InputAction[(int)EInputName.Max];
private void Start()
{
    mInput = new GeneralInput();
	mActions[(int)EInputName.Decide] = mInput.Game.Decide;
	mActions[(int)EInputName.Cancel] = mInput.Game.Cancel;

	mActions[(int)EInputName.Jump] = mInput.Game.Jump;
	mActions[(int)EInputName.Dash] = mInput.Game.Dash;
	mActions[(int)EInputName.Menu] = mInput.Game.Menu;
	mActions[(int)EInputName.Attack] = mInput.Game.Attack;
	mActions[(int)EInputName.Change] = mInput.Game.Change;
	mActions[(int)EInputName.Map] = mInput.Game.Map;

	mInput.Enable();
}

public bool isHold( EInputName in ) => mActions[(int)in].IsPressed();
public bool isTrig( EInputName in ) => mActions[(int)in].WasPressedThisFrame();
public bool isReleased( EInputName in ) => mActions[(int)in].WasReleasedThisFrame();

 はい。簡単ですね。ここまでは解説なしで大丈夫だとおもいます。

 

ゲームパッドを接続しているか?

static public bool HasPad() => Gamepad.current != null;

 基本的にはこれでOKです。ただし、ゲームパッドを差しているけどキーボードを使いたい人に対処したいなら、今入力しているものがパッドなのかキーボードなのかを検知し、その都度切り替えてあげましょう。

 

キーコンフィグと保存

 RebindingOperation というものを使います。
パラメータを色々とセットして Start() すると、キーを押すかキャンセルするかするまで待機します。onComplete まで来たらすでにキーバインドは変更されているので、わざわざセットする必要はありません。
 ついでに、キーバインドは SaveBindingOverridesAsJson で Json 取得可能なので、そのまま保存してしまいましょう。

InputActionRebindingExtensions.RebindingOperation mRebindingOperation = null;

public void rebindButton( int index = 0 )
{
    mInput.Disable();
	mRebindingOperation = mActions[mCursor].PerformInteractiveRebinding( index )
		.WithBindingGroup( "Gamepad" )
		.WithControlsHavingToMatchPath("<gamepad>")
		.OnMatchWaitForAnother( 0.2f )
		.OnCancel( op => onCancelKeyBinding() )
		.OnComplete( op => onFinishKeyBinding() )
		.Start();
	}
}


void onFinishKeyBinding()
{
	disposeOperation();

	// セーブする
	PlayerPrefs.SetString( "KeyBinding", mInput.Game.Get().SaveBindingOverridesAsJson() );
	PlayerPrefs.Save();
}

void onCancelKeyBinding() => disposeOperation();

void disposeOperation()
{
	mRebindingOperation?.Dispose();
	mRebindingOperation = null;
	mInput.Enable();
}

 index は何番目のキーコンフィグを変更するか指定します。

 上のコードでは Input を Disable / Enable していますが、別のスキームに差し替える方法もあるようです。Enable() 直後は謎の入力が入っていたりするので、ウェイトをかけるなどして二連続でキーコンフィグに突入しないよう注意してください。

 特定の行動にスティックなどを Bind したくない場合は

.WithControlsExcluding( "leftStick" )

 などをパラメータとして追加してください。
 キーボードを検知したい場合は、Gamepad の部分を二箇所 Keyboard にし、index を

mActions[mCursor].GetBindingIndex( InputBinding.MaskByGroup( "Keyboard" ) )

 のように取得してください。

 

キーコンフィグのロード

 ロードの場合は保存した String を LoadBindingOverridesFromJson で読みます。

public void loadKeyBinding()
{
	if ( PlayerPrefs.HasKey( "KeyBinding" ) )
	{
		try {
			mInput.LoadBindingOverridesFromJson( PlayerPrefs.GetString( "KeyBinding" ) );
		}
		catch
		{
			Debug.Log( $"[Keybinding] error" );
		}
	}
}

 ここで一点注意。General Input は new するだけでどのクラスでも使えますが、LoadBinding したキー設定は、そのインスタンスにしか適用されません*1。LoadBinding したインスタンスを使いまわしたい場合は、どこかに static な GeneralInput を持っておいて、それを Get() して使いましょう。

 

手動でボタンを書き換える

mInput.FindAction( "Decide" ).ApplyBindingOverride( 0, "<Gamepad>/buttonEast" );
mInput.FindAction( "Cancel" ).ApplyBindingOverride( 0, "<Gamepad>/buttonSouth" );

 これだけ。例えば Switch 環境だけ決定ボタンとキャンセルボタンを逆にしたい、みたいな設定は簡単。

コントローラを震わせる

public IEnumerator seq_vibrate( float power = 1f, float duration = 0.15f )
{
	Gamepad.current.SetMotorSpeeds( power, power );
	yield return new WaitForSeconds( duration );
	Gamepad.current.SetMotorSpeeds( power, power );
}

 これも簡単ですね。SetMotorSpeeds は二つの周波数の振動をコントロールできるようで、具体的にどういうモノかはお手持ちのコントローラで試してみてください。

ボタンアイコンの表示

 これは少しめんどいです。でも、最近のゲームは大体やってるので根性で頑張りましょう。

 まず、TextMeshPro にスプライトアイコンを表示する……あたりのくだりは省略します。いい感じに全ボタン分のアイコンを設定してください。

//--------------------------------------------------------------------------
static public string GetSpriteName( string device_layout_name, string controlPath )
{
	return GetSpriteName( GetPadType( device_layout_name ), controlPath );
}

static public string GetSpriteName( EPadType pad_type, string controlPath )
{
	var prefix = pad_type == EPadType.XBox ? "XB" : pad_type == EPadType.DualShock ? "PS" : "GP";
	switch( controlPath )
	{
		case "buttonSouth":		return prefix + "_S";
		case "buttonNorth":		return prefix + "_N";
		case "buttonEast":		return prefix + "_E";
		case "buttonWest":		return prefix + "_W";
		case "start":			return prefix + "_ST";
		case "select":			return prefix + "_SE";
		case "leftTrigger":		return prefix + "_L";
		case "rightTrigger":	return prefix + "_R";
		case "leftShoulder":	return prefix + "_L2";
		case "rightShoulder":	return prefix + "_R2";
		case "leftStickPress":	return prefix + "_L3";
		case "rightStickPress": return prefix + "_R3";
		case "dpad":			return "LStick";
		case "dpad/up":			return "Up";
		case "dpad/down":		return "Down";
		case "dpad/left":		return "Left";
		case "dpad/right":		return "Right";
		case "leftStick":		return "LStick";
		case "rightStick":		return "RStick";
	}

	return "INVALID";
}

//--------------------------------------------------------------------------
static EPadType GetPadType( string device_layout_name )
{
	if ( InputSystem.IsFirstLayoutBasedOnSecond( device_layout_name, "DualShockGamepad" ) )
	{
		return EPadType.DualShock;
	}
	else if ( InputSystem.IsFirstLayoutBasedOnSecond( device_layout_name, "XInputController" ) )
	{
		return EPadType.XBox;
	}
	else return EPadType.Gamepad;
}

static public string GetSpriteNameOfKeyboard() => "KB_KEY";

 なんとなく分かったでしょうか。pad_type と controlPath によって適切なボタンの Sprite アイコンを呼んでいます。ただ、キーコンフィグを想定するとどのアクションにどの controlPath が設定されているのかわからないので、 GetSpriteName の呼び方にコツがあります。

public string getSpriteName( string action_name )
{
	var act = mInput.FindAction( action_name );
	if ( act == null ) return "";
	if ( !HasPad() )
	{
		var b = act.GetBindingIndex( InputBinding.MaskByGroup( "Keyboard" ) );
		act.GetBindingDisplayString( b, out var deviceLayoutName2, out var controlPath2 );
		return $"<sprite name=\"{GetSpriteNameOfKeyboard()}\">{controlPath2.ToUpper()}";
	}
	else
	{
		act.GetBindingDisplayString( 0, out var deviceLayoutName, out var controlPath );

		return $"<sprite name=\"{GetSpriteName( deviceLayoutName, controlPath )}\">";
	}
}

 特定のアクションに割り振られているキーは GetBindingDisplayString で取得します。キーボードの場合はキーが返ってくるのでよしなにしてください。一番目の引数は例によって index なので、メインキー、サブキーを併記したい場合はそんな感じに改変してみてください。

 

まとめ

 大体ゲームに必要な機能は網羅できたとおもいます。よき new input system ライフを*2

 え?よく分からなかった? そうかもしれません……でも大丈夫! そんな人のためにサンプルプロジェクト&UnityPackage も作りました。コインいっこでね。

 こちらからどうぞ↓

note.com

 

*1:これに気付かなかったため、アリスではマスター直前まで「キーコンできてるように見えてできてなかった」致命的な不具合が存在した。

*2:Rewired への恨み節は割愛します……

Unity バージョンの選び方のヒント

 いつものように前口上書いているうちにテンション下がるので本題から。

理由がなければ LTS

  • 最新メジャーバージョンは Experimental*1どうしても最新機能を使いたい理由が無い限り、LTS が出ているメジャーバージョンを使う。
  • LTS は2年間のサポートが保証されるだけでなく、以後のバージョンで修正された不具合も遡って修正されることがあるので、名目上は最も安定している。
  • 初期ほどの不安定さはないものの、Unity 自体が様々な機能を持ち、様々なプラットフォームで動作する巨大なプロダクトであるため、最新バージョンには結構な確率でとんでもない不具合が潜んでいる。

できるかぎり最新のメジャーバージョン

  • メジャーバージョンが上がるとエディタの使い勝手が結構変わったりして、ユーザ的にはお気に入りのバージョン、あんまりお気に入らないバージョンがあるとは思うが、そんなことを言っていられるほど開発環境というのは甘くない
  • なぜなら、PC 以外のほぼすべてのプラットフォームで、リリースできる Unity バージョンは極めて狭く制限されているからである。
  • コンシューマではマスター提出可能バージョンなどと言われており、マスターアップ時に必ず指定されたバージョンでなければ QA で弾かれる。
    • 一度出してしまえば、パッチ等で更新する時に古いバージョンの開発環境のままであっても不問申請が可能。
  • モバイルでは時折唐突に更新されるガイドラインに従って、ROMを更新する必要があり、その要件を満たすために新しいバージョンの Unity を求められることがある。
    • 最新である必要はないことが多いが、リリース5年後でも対応が求められる。
    • Android の場合は提出可能 Android バージョンが容赦なく上がっていくので、最新付近の環境を求められる。
  • そもそもゲーム制作が2年以上に及んだ場合、作っているうちにマスター提出できないバージョンになってしまったりするので、更新の必要は出てきたりするのだが……。
  • (幸い、Unity5->Unity2017の時に起きたような壊滅的なプロジェクト破壊は最近はあまり起きないのでバージョンアップくらいなら割となんとかなる)

できる限り古いマイナーバージョン

  • 例えばバージョンが 2021.3.20f1 であったら、この「20」にあたるのがマイナーバージョンだが、ここはできる限り古い値にしておきたい。なぜかというと……
  • 残念なことに、Unity の LTS は LTS であるにもかかわらずに結構な不具合が潜んでいることがあり、バージョンが一つ違うと修正される、あるいは発現する不具合がある。
  • コンシューマにおいては更にその足並みは混沌を極める。例えばゲーム機 A の◯◯という機能を使った場合に起こる不具合が 3.10f1 で修正された一方で、別の□□という機能を使った場合に起こる不具合が 3.16f1 から発現し、それがいまだ修正されていない、みたいなことがままある
  • しかたないから 3.15f1 で開発していると、ゲーム機 B では 3.14f1 から発生したとある不具合が致命的でマスターできなくなる、なんてことが起きる。最近の Unity では比較的安定しているとはいえ、基本的に開発環境のダウングレードは避けたい。
  • なので、マイナーバージョンはできる限り古いものを利用し*2、自分のプロダクトにクリティカルな不具合が出た場合のみ、それが修正されたバージョンへと上げるべきである。英語のリリースノートとにらめっこしながら最適なマイナーバージョンを選ぼう。地獄である

開発中はあんまり更新するな!

  • 「そういえば最近、ここの表示おかしいな……いつからだ……?」と追ってみると、なぜか実装時のリビジョンからおかしくなっており、辿ってみれば結局 Unity のバグだったということが結構ある。Unity もマイナーバージョン一つ上げるのに何千とあるアセットやシェーダとの整合性を確認することは難しく、多少の不具合は仕方ない。
  • が、最新が出たから更新シヨーみたいな気持ちで更新しまくると、自分が世界で初めて見つける不具合にもまあまあ出会う。お前が報告するんだよ!
  • というわけで、開発中にあんまり更新するのはやめよう。マスターを見据えるようになった時期に、最適なマイナーバージョンを選び、あとは祈るのみである。幸あれ。

 

まとめ

  • できるかぎり最新の LTS を使い、マイナーバージョンは古いものにする
  • 開発中はあんまり更新しない
  • アップデートする時は祈れ

以上!

*1:執筆時点で2022がβ、2023がα。6月に2022のLTSが出るらしいが……?少し待ったほうがいいかもしれない。

*2:とはいえ、3.0f1 には高確率で変なバグが仕込まれていたりするので、リリースノートを見ながらちょっと後ろのバージョンにしよう

エルデンリング雑感 名作だが、ぼくらはラーヤに気付くことができない

 一日一時間ずつ遊んだエルデンリングをようやくクリアしました。

 クリアタイムは74時間なので、ほぼ丸二ヶ月。いやー長かったですね。特にソウルシリーズは初めてだったので、最初の方は大分苦労しましたし、マルギットの洗礼も漏れなく受けました。終盤はほぼ雫先生のお世話になったので、大分イージーゲーマーと言っていいでしょう。一番苦労したのはマレニア。

 ゲームデザインとしても大いに参考になるゲームだったので色々書きたいことはあったんですが、クリアするまで批評というものは書けないもので、ようやく話せます。ネタバレ全開でいくので未クリアの人は注意してください。あと、結構厳しいことも書きます。

クリア時のレベルとプレイ時間

1. 紛うことなき神ゲー

  • (+) 最序盤から終盤まで、気の抜けないゲームプレイ。ダレることなく最後まで楽しめた
  • (+) 広大なフィールドの端から端まで敵がみっちり詰まっている。無数のダンジョン、無数の仕掛け、無数のボス。そして、その全てが洗練されたアートによって埋まっているという物凄い物量。
  • (+) ビルドや武器の選択肢の広さ。前述した広大なフィールドに散りばめられた武器一つ一つに特色があり、少なくない数の固有武器と専用戦技が用意されており、そのすべてを遊び尽くすのは難しいほど。
  • (+) 鮮烈なキャラクターデザイン。ラスボスかと見紛う貫禄の最初のボス。デミゴッド一人一人の英傑ぶりがその姿と描写を通して伝わり、説得力を持っている。攻撃方法も多彩で、一つ一つのボス戦がとても魅力的に仕上がっている。
  • (+) とにかく、世界観の構築に関しては比類なき完成度と言える。そびえ立つ黄金樹を望む荒涼とした大地のあの空気感は多くのプレイヤーの胸に刻まれただろう。数多の強敵の恐怖も添えて。

と、このゲームが傑作であることは枚挙に暇がないのですが、この辺にして。

 

2. ゲーム体験がリニアすぎて、オープンワールドとは言い難い。

展開が結局一本道

  • 優れたオープンワールドのシナリオでは、本流たるメインシナリオと、その中で出会う街や人が織りなすサブシナリオが存在し、その中に数多のサブクエスがゲームを形作っています。が、エルデンリングはメインシナリオとサブクエストしかありません。
  • オープンワールドで街へ到達すると、その街には独自の暮らしがあり、歴史があり、住む人々とその悩みがあるので、一気にシナリオが横向きに広がります。しかし、エルデンリングには街がありませんので、そういうこともありません。
  • オープンワールドでは二次元的に行動範囲が広がっていく体験が人に自由度を感じさせますが、エルデンリングではある程度決まった順番でしかフィールドが解放されません。また、そのフィールドをクリアせずスルーする選択肢はあるものの、それもまた二択に過ぎません。
  • エルデンリングにもラニイベントや火山館、セレン、アレキサンダーなど固有NPCに付随したシナリオはいくつか存在しますが、それらはバラバラのタイミングで発生するただの連続イベントに過ぎず、また受注後の過程でメインシナリオを進める必要があるので、どちらかというと縦向きのシナリオと言えます。例えば、○○のイベントを進めたいから次はこの方向へマップを開拓しよう、という選択をプレイヤーが取れるようになれば、オープンワールドらしいシナリオの広がりを得ることができます。以下図:

全部なぎ倒してエルデの王になるしかない

  • このゲームは神話なので、未来の王たる褪せ人くんは迫りくる敵をすべてなぎ倒してエルデの王になりました、というシナリオをなぞるしか選択肢がありません。これはもう、仕方がないことだと思います。狭間の地は現時点でほぼ滅んでますし、ビルド&スクラップしか残されてないかもしれません。
  • しかし、ゲームの可能性は無限大です。ラニに従ってマレニアをボコってラダーンの正気を取り戻し、黄金樹を焼かずに新たな律を勝ち取るシナリオはどうでしょう。マリカに従ってフィアを正ヒロインとし、蘇ったゴッドウィンを王とするシナリオは? ゴッドフレイともっと早く出会っていれば戦友になったかもしれませんし、レアルカリアを復興させて狭間の地を統べるのもいいですね。そうなれば、狂い火に従って黄金樹を焼き、この地を作り変えるエンドも生きてきます。
  • もちろん、こうなってくると工数はやや増えますが、そこは他の部分を削るしかないですね。実際は、データ部分が主ですのでそこまで破滅的に増加することはないと思います。それよりも、複数の異なるシナリオを束ねてプランニングするほうが遥かに難しいので、ボトルネックになるのはそこでしょう。今までソウルシリーズはオープンワールドではなかったので、その知見があるディレクター・プランナーが居なかったのも大きいと思います。

ダンジョンの作り方が下手

  • 多くの人がストームヴィルで、レアルカリアで、王都や崩れ行くファルムアズラで、「本当にこの道で合っているのか……?」と何度も思ったことでしょう。エルデンリングのダンジョンは複雑怪奇です。多層構造になっているのでマップは役に立たず、屋根の上や天井の梁を平気で通らせるくせにそれがメインルートであるかどうかは祝福に至るまでわかりません。
  • 複雑なマップでは、プランナーはプレイヤーの自然な誘導に非常に気を使わなければなりません。建物に入った瞬間、最上階にボス部屋っぽい構造物が見えれば、とりあえず階を上に上がっていけばよいと理解するでしょう。明るい道と暗い道、細かい意匠の施された道とそうでない道、敵が大事そうに守っている道なんかも効果はてきめんです。祝福がせっかく見やすいエフェクトを発しているので、道中でちら見せさせればプレイヤーを眼の前の敵に集中させることもできるのですが、そういった活用をしている箇所はほぼありませんでした。

3. ストーリーが分かりづら過ぎる

ゲームをクリアするだけでは何もわからない

  • 本作のストーリーはつまるところ、
    黄金律なんてやっぱりクソだと気付いたマリカがラニ達と協力してゴッドウィンを殺してエルデンリングをぶっ壊したらその破片を拾ったデミゴッドたちが争い始め(破砕戦争)、狭間の地もぶっ壊れた。二本指とかいう黒幕は黄金律を直そうと思って褪せ人くんを呼んだが、マリカラニ金仮面卿三本指ら思惑の違うヤツらがよってたかって褪せ人くんを誘惑して自分の『律』を作ろうとするのでさあこの世界の運命はいかに」*1
    という感じでしたが、クリアした人は知ってましたでしょうか。まず、普通にクリアするだけではそれを殆ど理解できません。
  • デミゴットたちは出会ったりボコボコにすると意味深な台詞を吐いていくのですが、ストーリーの本筋はアイテムの説明文やワールド上に置かれた石碑で補完する必要があり、多くの人にとってはまとめサイトを読んだ方が早いことになります。
  • 色んな裏設定をゲーム内に散りばめて、考察の余地を残すことは素晴らしいことです。が、ストーリーの本筋くらいはちゃんと分かるようにしなさいよ。殆どの褪せ人くん(プレイヤー)はわけも分からず片っ端からデミゴッドをぶっ殺しまくったただの狂人だよ。
  • そもそも、登場人物が多すぎます。主要人物だけ挙げてもマリカ、ラダゴン、メリナ、レナ(ラニ)、レナラ、そこにゴドリック、マルギット、ラダーン、モーゴッド、ライカード、ゴッドフレイ、ゴッドウィン。そして二本指やら円卓の人々やら大量に出てきて、正直名前を聞いても「誰だっけ?」となることのほうが多かったくらいです。ラ行多すぎか。ゲーム内にこの人物相関図置いといてほしかったですね。

重要人物がオープンワールドの中に埋没する

  • 誰もが感じたと思いますが、フィールド上のNPCの殆どは壮大な黄金樹を望むフィールドの中に埋没します。多くの人は、アルター高原の巨人に気を取られラーヤの姿に気付くことができない。(以下スクショ無かったので引用)

  • ただでさえ登場人物が多すぎて誰が誰かもわからないのに、発見もしづらく、クエストリストもなく、円卓でヒントを得られるわけでもない。気がつけば辺境の地で鈴玉と化していることもしばしば。出会ったこともないエドガーに言われもない怨恨を抱かれて思いました。攻略サイト見ようと。
  • ベゼスダのオープンワールドゲームなんかは、フィールド上にポツンと置かれたNPCも、目立つように戦闘してたり、アクションしてたり、発光してたり、こっちに駆け寄って話しかけてきてくれるんですよね。いや、よく出来てる。当時は何も思わなかったけど、実は色んな工夫が凝らされていたんですね。
    BotW なんかは元々キャラクターがフィールドに対してちゃんと目立つようにデザインされているので、道端に置かれていてもスルーすることがほぼ無かった記憶があります。

4. ゲームシステムが噛み合ってない

アイテム製作、使いましたか?

  • 「え、アイテム製作ってなんだっけ?」とこの時点でなる人がいても驚きはしません。実際、ぼくは中盤までツール鞄の存在を見逃していたのでアイテム製作を使えませんでしたし、できるようになってからもほぼ使いませんでした。
  • アイテム製作というシステムとエルデンリングが如何に噛み合ってないかは、以下のような理由が挙げられます。
    1. 死んで覚えるボス戦と消費アイテムは相性が悪い
    2. あちらこちらに材料が落ちている割には、いざ必要となると全然足りない(素材の購入がほぼできない)。
    3. そもそも使いたい消費アイテムがあんまりない
    4. 製法書があまりにも散らばりすぎていて、攻略サイトでも見ないと回収不可。
  • 唯一よく使ったものといえば腐敗の苔薬くらいでしょうか。素材の一つがレアアイテムなので(なぜ?)作りづらいですが……。*2
  • 消費する上に FP も消費するようなアイテムは、一体何がしたいんでしょうか?
  • もし、完成したエルデンリングからアイテム製作だけなんとかするとしたら以下のような感じでしょうか。
    1. 普通に HP や FP を回復するアイテムを入れる。一定時間バリアや自動返礼、透明化のような、対敵ではなくダンジョン攻略に役に立つアイテムを入れる。
    2. 製法書ではなく、素材の鈴玉のようなものを各地に散りばめ、それさえ入手すれば NPC がその素材を無限に売ってくれるようにする。(もちろん、フィールド上でしか手に入らないアイテムもある)
    3. ちゃんとそのヒントを示唆してくれるような NPC を置く。
  • まあ、正直「なくてもいいシステム」はゲームの面白さを阻害するものではないので、別にいらないならいらないでもいいんですが……なんか勿体ないですよね。

ほとんどの報酬は無用の長物である

  • 冒頭でビルドや武器の選択肢が広いと書きましたが、裏を返せばプレイヤーが選ばないビルドや武器のほうが圧倒的に多いわけです。ステータスの振り直しも有限ですし、一周回一ビルドでいい。ボスによって武器を持ち替えることもほぼありません。
  • よって、様々なダンジョンにボス報酬として置かれた武器や魔術や戦灰や遺灰なんかはほとんどが無用の長物になってしまいます。ただのコレクションですね。まあ、ボスを倒してダンジョンをクリアすること自体が楽しみの一つなんで、報酬はあくまでオマケとも捉えられるんですが……。
  • たとえば、
    1. 属性をもっと前面に出して、ボスやフィールドの特色に因って武器や魔術や戦灰や遺灰をガチャガチャ入れ替えるようなシステムにする(ちょっとめんどくさい)
    2. サブスロットのようなものを作り、メインでない武器や遺灰をセットするとステータスに影響が及んだり攻撃に追加効果が発生したりといった副次効果を入れる
    3. 遺灰を同時に複数使えたり、遺灰に武器を持たせられるようにする(ゲーム性が変わってしまう……)
    4. そもそも褪せ人を複数人のチームにして、各々にビルドを用意する必要があるシステムにする(ソシャゲ方式)
  • あたりは考えられますが、根本的な解決とは言い難いです。自分だったらそもそもゼルダの伝説のリンクのように、剣と弓は最低でも使う、といった装備の種類を増やす方向で行くと思います。あとは武具改造。
  • ただ、個人的にはモンハンのようなぶっ倒しても素材しか手に入らないので何度も伝説のドラゴンを狩りまくる必要があるような作りよりは現状のほうが好きです。報酬システムはまだまだ答えが出ません

戦技システムと固有武器はバッティングしているのでは?

  • 今作では武器に戦灰を付けることにより、同じ武器でも違う戦技を使うことができます。その組み合わせ、無限大!……が、専用戦技の方が強くないですか
  • 実際、今回は魔法剣士ビルドで早々と名刀月隠を手に入れてしまったので、これより強い武器+戦技の組み合わせは早々ありませんでした。脳筋ビルドなら二刀流があるのでもう少し広がるかもしれませんが。
  • 結局、専用戦技は少し強めに設定されているので、色んなビルドを試せるというシステム自体は生きていますが、普通にゲームを進めていく中では結局専用戦技持ちの固有武器に落ち着いていくと思います。ちょっと勿体ないですね。
  • 個人的には、出血武器に冷気の戦技つけたり、聖属性武器に即死つけたりして光と闇が合わさって最強に見える武器作ったりしたかったですね。ちょっと自由度が低め。

 

5. 総論

  • ゲーマーならまずやるべき名作。粗はあるが、それを加味しても世界観の作り込みと戦闘の面白さは圧巻。
  • 一方で、エポックメイキングな作品になるような要素はなく、あくまでソウルシリーズの延長線上という位置づけ。オープンワールドとの融合による化学変化などは無し。
  • ともあれ、神話を追体験するという唯一無二のプレイ体験を得られるので、時間と根気があればぜひプレイすべき一作。

 

 

 

*1:前半部分を厳密に書くと、8人産んだ結果まともな神人が生まれない=黄金律に欠陥があることに気付いたマリカは黄金律に死の回帰が無いことが原因と考え、寵愛するゴッドウィンを死のルーンで殺害して死王子のルーンを得ることを考えたが協力者であるラニが肉体の死のために死のルーンの片割れを使ってしまったので失敗。仕方ないので黄金律そのものであるエルデンリングをぶっ壊そうとしたものの半身であるラダゴンが抗って修復したためそれも失敗(OPムービーの冒頭が壊して直しての2コマ漫画になってることに気づくと笑えます)。破砕戦争を経て狭間の地はにっちもさっちもいかない状況になりましたとさ。という感じです。皆さんの解釈も同じでしたか?

*2:というか、もう直接腐敗の苔薬をフィールド上に置けばよくて、アイテム製作とか必要ないのでは

チュートリアルの作り方:チュートリアル作成における指標のメモ

f:id:eiki_okuma:20200803143037p:plain

 ゲームのチュートリアルを作る際にヒントになりそうな指標を記す。チュートリアルを考える時、その取っ掛かりとしてあらゆる提示情報を
 「プレイヤーが知っているもの」
 「プレイヤーが自発的に試すもの」
 「こちらから提示する必要があるもの」
の3つにフェーズ分けして考えていく。

 

続きを読む