変数
シナリオ変数を使用すると、ユーザー定義の値を作成・変更し、それらを使ってシナリオスクリプトやその他のシステムの条件付き実行を制御できます。たとえば、プレイヤーの選択に基づいて再生するシナリオスクリプト(シナリオルート)を切り替えるために変数を使用できます。もう1つの一般的な用途は、ゲーム中の選択に応じてプレイヤーのステータス(スコア、所持金、リソースなど)を追跡することです。
注意
変数名に使用できるのは文字、数字、アンダースコア、ドットのみで、数字で始めることはできません。例:score、Char1Score、my_score。ドットは スコープ と ローカル変数 のために予約されています。名前は大文字と小文字を区別しません。つまり、myscore という名前の変数を作成したあとで MyScore として参照することも、その逆も可能です。
変数は @set コマンド(および他のコマンドの一部のパラメーター)で作成・変更でき、@if や @while のプライマリパラメーターなど、式コンテキストを持つ任意のパラメーターで使用できます。たとえば、次のスクリプトは score の値に基づいて実行先を切り替えます。
; 「score」変数を作成します。
@set score=0
; ある時点で、プレイヤーの選択に基づいて変数を変更します。
@choice "良い決断" set:score++
@choice "悪い決断" set:score--
...
; 後で、条件付き実行に変数を使用します。
@if score is above 10
@goto GoodEnd
@else
@goto BadEnd— 変数のさまざまな使用例は @set コマンドのリファレンスで確認できます。
ヒント
score is above 10 式では > 演算子の代わりに is above エイリアスを使用しています。演算子のほうが好みであれば、@if score > 10 と書くこともできます。サポートされている構文について詳しくは、シナリオ式ガイド を参照してください。
変数の注入
コマンドパラメーターが式コンテキストでなくても、中括弧を使用して変数を注入できます。
; 3つの変数に値を代入します。
@set posX=0, posY=0.5, time=1.5
; それらを「char」コマンドのパラメーターへ注入します。
@char Kohaku pos:{posX},{posY} time:{time}汎用テキスト行内でも同じことができます。
; プレイヤーにテキスト入力を促し、「name」変数に代入します。
@input name summary:"あなたの名前を選んでください。"
; 代入された「name」変数を注入します。
Archibald: ようこそ、{name}!ヒント
キャラクター名を動的にするには、表示名 機能を使用してください。
パラメーターの型が許可する限り、任意のパラメーター値に変数を注入できます。たとえば、数値パラメーターに文字列(テキスト)を代入することはできません。
@set yPos=0.1, tint="lightblue"
; 「tint」は数値ではないため、以下はエラーになります。
@char Kohaku pos:50,{tint}
; ...こちらは正常に実行されます。
@char Kohaku pos:50,{yPos} tint:{tint}メタ変数
デフォルトでは、シナリオ変数は現在のゲームセッションに限定されます。プレイ中に変数へ値を代入したあとで、プレイヤーが新しいゲームを開始したり、その変数が代入されていない別のセーブスロットをロードしたりすると、その値は失われます。この動作はほとんどの種類の変数に適しています。変数をゲームセッションから「切り離したい」場合は、@set コマンドで初期化するときに meta! フラグを使用します。
@set myMetaVariable=0 meta!メタ変数は、ルートクリア状況、累計ゲーム統計、実績など、個別のゲームセッションより上位の「メタ」情報を追跡するのに便利です。
; 「X」と「Y」ルートのクリア状況を追跡する変数を定義します。
@set completeRouteX, completeRouteY to:false meta!
...
; 後のスクリプトのどこかで、「X」ルートをクリアしたとき。
@set completeRouteX=true
; これでタイトルスクリプトで特別なものを表示できます。
@if completeRouteX and completeRouteY
@showUI TrueRouteTitle
@else
@showUI DefaultTitleヒント
一度だけ増加するメタカウンターが必要な場合(ロールバックやゲーム再起動後の再プレイでも再度増加しないようにする場合)は、hasPlayed() 式クエリ を使用してください。
@set metaCounter=0 meta!
...
@set metaCounter++ unless:hasPlayed()変数スコープ
変数名の前にスコープ名とドットを付けることで、シナリオ変数をスコープの下にまとめることができます。
@set stats.strength=1
@set stats.agility=3
@if stats.agility is above stats.strength
...スコープ付き変数は、route.complete、stats.complete、quest.complete のように、複数のシステムが同じ短い名前の変数を必要とする場合に便利です。
@set コマンドで複数の変数に値を代入するときは、scope パラメーターを使用して各変数に同じスコープを適用できます。
@set strength, intellect, agility to:0 scope:stats
@set stats.agility++ローカル変数
名前がドットで始まる変数は、それが使用されているシナリオスクリプトファイルに限定されたローカル変数になります。
@set .count=0
@while .count is below 10
@set .count++
現在のカウント:{.count}各シナリオスクリプトは独自のローカルスコープを持つため、あるスクリプトの .count が別のスクリプトの .count と競合することはありません。ローカル変数は、スクリプト内部のカウンター、一時的なルート状態、プロジェクト全体で有効な名前を必要としない補助値に使用します。
デフォルト代入
デフォルト代入は、変数にまだ値がない場合にのみシナリオ変数へ値を代入します。変数が初期値を持つことを保証したいが、すでに設定されている場合は上書きしたくないときに便利です。
デフォルト代入を行うには、?= 演算子を使用するか、@set コマンドで init! フラグを追加します。
; 「foo」をデフォルト値0で初期化します。
@set foo?=0
; 3つの変数をデフォルト値で初期化します。
@set foo=0, bar=false, baz="" init!meta! または const! フラグを使用すると、自動的にデフォルト代入として扱われるため、それらと一緒に ?= 演算子を指定する必要はありません。
; ルートクリア状況を追跡する両方の変数を宣言し、「false」を代入します。
; 同じスクリプトが再度再生された場合(たとえば次回のゲーム開始時)でも、
; 変数は再代入されません。
@set clearedRouteX, clearedRouteY to:false meta!変数イベント
カスタムUI やその他のシステムを構築するとき、変数の値が変わったタイミングで反応したい場合があります。たとえば、キャラクターのステータス画面を作成する場合、変数に応じてテキストを更新したいことがあります。通常はC#スクリプトを使いますが、Variable Events コンポーネントを使用することもできます。このコンポーネントは、指定された名前の変数が変更されたときにUnityイベントを呼び出します。
変数のデバッグ
ゲームの実行中に、デバッグ目的ですべての既存の変数を表示・変更できます。
~ キーで開発コンソールを開き、var コマンドを入力して変数エディターウィンドウを開きます。
リスト内の変数の値を変更すると「SET」ボタンが表示されます。それを押すと変更が適用されます。
ゲーム実行中にシナリオ変数が変更されると、変数リストは自動的に更新されます。
C#でのシナリオ変数の使用
シナリオ変数は、IVariableManager エンジンサービス を介してC#からアクセスできます。
新しい変数を作成するには、AddVariable メソッドを使用します。
var vars = Engine.GetService<IVariableManager>();
// 「こんにちは、世界!」の値を持つ「myVar」文字列変数を作成します。
vars.AddVariable(new("myVar", new("こんにちは、世界!")));メタ変数または定数を作成するには、種類を指定します。
// ルートクリア状況を追跡するブール値のメタ変数を作成します。
vars.AddVariable(new("clearedRouteX", new(false), VariableKind.Meta));変数値を取得・設定するには、それぞれ GetValue と SetValue メソッドを使用します。たとえば、myVar という名前のシナリオ文字列変数が存在する場合、以下のコードはその値を取得し、それに「Hello!」を追加して、変更した値を設定し直します。
if (vars.GetValue("myVar") is { String: var text })
vars.SetValue("myVar", new(text + "Hello!"));変数の実際の値を取得するときに .String プロパティを使用していることに注目してください。変数は String、Numeric、Boolean の3つの型のいずれかになります。型は、シナリオスクリプトで変数が最初に代入されたときに決定されます。
; 「foo」変数に「こんにちは、世界!」文字列値を代入します
@set foo="こんにちは、世界!"
; 式で文字列値を使用します
@if foo is "こんにちは、世界!"
; 「bar」変数に数値42を代入します
@set bar=42
; 式で数値を使用します
@if bar is above 12
; 「baz」変数にブール値trueを代入します
@set baz=true
; 式でブール値を使用します
@if baz— または、C#では次のようになります。
var vars = Engine.GetService<IVariableManager>();
// 「foo」変数に「こんにちは、世界!」文字列値を代入します
vars.SetValue("foo", new("こんにちは、世界!"));
// 代入された文字列値にアクセスします
if (vars.GetValue("foo") is { String: "こんにちは、世界!" })
// 「bar」変数に数値42を代入します
vars.SetValue("bar", new(42));
// 代入された数値にアクセスします
if (vars.GetValue("bar") is { Number: > 12 })
// 「baz」変数にブール値trueを代入します
vars.SetValue("baz", new(true));
// 代入されたブール値にアクセスします
if (vars.GetValue("baz") is { Boolean: true })C#でシナリオ変数の型を確認するには、値の .Type プロパティを使用します。
if (vars.GetValue("bar") is { Type: VariableValueType.Numeric } value)
if (value.Number > 12) // これで「.Number」値に安全にアクセスできますあるいは、Try... オーバーロードの1つを使用します。
vars.TryGetValue<float>("MyFloatVarName", out var floatValue);
Debug.Log($"My float variable value: {floatValue}");
vars.TryGetValue<int>("MyIntVarName", out var intValue);
Debug.Log($"My integer variable value: {intValue}");
vars.TryGetValue<bool>("MyBoolVarName", out var boolValue);
Debug.Log($"My boolean variable value: {boolValue}");
floatValue += 10.5f;
vars.TrySetValue("MyFloatVarName", floatValue);
intValue = -55;
vars.TrySetValue("MyIntVarName", intValue);
boolValue = !boolValue;
vars.TrySetValue("MyBoolVarName", boolValue);すでに存在する変数に対して AddVariable を呼び出したり、存在しない変数に対して SetValue を呼び出したりすると例外がスローされることに注意してください。毎回 VariableExists を確認したくない場合は、UpsertValue ヘルパーメソッドを使用してください。変数が存在しない場合は自動的に作成し、存在する場合は値だけを更新します。
// 「foo」が存在する場合は42を設定します。
// 存在しない場合は、デフォルト値42の「foo」を作成します。
vars.UpsertValue("foo", new(42));