UEFN Verse言語 メタバース

【2023年】UEFNのVerseで関数の結果を指定する方法

【2023年】UEFNのVerseで関数の結果を指定する方法
みなみ

UEFNのVerse言語で関数の結果を指定する方法について教えてください!

りゅう

初心者向けにわかりやすく解説してほしいですね!

こんなお悩みを解決します。

 本記事の内容
 本記事の信頼性

この記事を書いている僕は、金融系専門卒の投資家兼ブロガーです。実際にUEFNを使っており、現在進行形で学んでいます。

今回は、UEFNのVerseで関数の結果を指定する方法について解説していきます。

さっそく、やっていきましょう。

あすか
結果の指定を学ぶまえに【前提】

関数はアクションを実行することができます。

また、関数を呼び出すことで特定の処理を実行し、その結果として値を返すこともあります。この返される値を「結果」と呼びます。

例えば、GetRandomInt(1, 10) を呼び出すと、1から10までのランダムな整数を取得できることが期待されますね。

関数の戻り値の型を変更するには、関数シグネチャの型を変更します。

具体的な例は以下のとおり。

GetNumberOfMousetrapsYouCanAfford() : int

この場合、GetNumberOfMousetrapsYouCanAfford() 関数の戻り値の型が int に設定されており、この関数を呼び出すと整数が返されることが期待されます。

GetNumberOfMousetrapsYouCanAfford() : float

逆に、戻り値の型を float に変更すると、異なる型の値が返されます。

関数の戻り値の型が指定されている場合、その関数の本体(コードブロック)では、その型に一致する結果を生成する必要があります。

もし結果を生成しない場合、コードはコンパイルエラーとなりますね。

これはつまり、関数が宣言された型の結果を返すことが要求されているということです。

以降では、この問題を回避する方法について学んでいきましょう。

結果と戻り値

結果と戻り値

結果とは、関数を実行した際にその関数から返される値を指します。

以前、「キーワード」について解説しました。

※キーワードは、プログラミング言語に組み込まれた特定の単語であり、それぞれが特定のアクションや処理に関連しています。

Verse では、return も、return キーワードの後に続く式から生成される値を結果として提供するよう関数に指示する キーワード です。

MyFunction() : int =
    return 5

OnBegin<override>()<suspend> : void =
   MyFunction() # result is 5

上記の例のコードでは、MyFunction()が呼び出されたときに5の値を返します。

returnキーワードを明示的に含めなくても、関数には問題が発生しませんが、returnを明確に指定することをおすすめします。

早期のreturn

プログラムにおいて、return文が実行されると、その関数のコードブロックは即座に終了します。

つまり、return文の後に続くコードは実行されません。

この機能は、特定の条件が満たされた場合に関数を早期に終了させる際に便利です。

以下の関数は、CoinsPerMouseTrapに基づいてCoins変数を更新します。

ただ、ネズミ捕り器を購入するためにはCoins変数が正の値である必要があります。

もしCoinsが負の値である場合、関数はエラーメッセージを表示して戻り値を返します。

このような場合、関数の残りのコードを実行する必要はありません。

実際には、return文を使用しない場合、この関数ではCoinsの値が誤って減少し、Coinsが負の値であることが示されません。

var Coins : int = -10
CoinsPerMousetrap : int = 100

BuyMousetrap() : void = 
    if (Coins < 0):
        Print("Error: Coins set to negative value")
        return
    set Coins = Coins - CoinsPerMousetrap
    Print(“Mousetrap bought! You have {Coins} coins left.”)

return文を使用して関数を早期に終了する場合、コードの実行フローが予想外の結果となり、バグが発生する可能性があります。

具体的には、return文がPrint(“Mousetrap bought!You have {Coins} coins left.”)よりも前に実行されると、関数から抜ける前にCoinsの新しい値が出力されず、結果として意図しない挙動になります。

var Coins : int = 500
CoinsPerMousetrap : int = 100

BuyMousetrap() : void = 
    if (Coins < 0):
        Print("Error: Coins set to negative value")
        return
    set Coins = Coins - CoinsPerMousetrap
    return
    Print(“Mousetrap bought! You have {Coins} coins left.”)

コードに早期のreturn文が存在しても、通常はコンパイルは成功します。

しかし、Visual Studio Codeなどの統合開発環境では、return文の後に続く式が実行されないことを警告として表示することがあります。

有益な結果のない関数のVoid

結果が必要な場合と必要ない場合があります。

レッスン2では、異なる型について学習しましたが、それぞれの型には特定の種類の値が必要であることも覚えているでしょうか。

以下は、簡単なリストですが、Verseでは多様な型が使用されます。

これらの型は、変数や定数を使用する際の基本的な要素となります。

動作
logicTrue または False のいずれかTrue / False
int整数整数値
float小数小数点
stringテキスト(文字列)文字列、数字、句読点、スペース、絵文字
※スマホの方は→にスクロールできます。

関数の戻り値が不要な場合、その関数の型を void に設定することができます。

つまり、関数の型を void にすることで、コードブロックの最後の式でどの型の結果でも生成せずに、コンパイルエラーを回避することができます。

void 型の関数では、return キーワードを使用することも可能ですが、その際には値を提供する必要はありません。

練習問題

UEFN Verse 結果を指定する練習問題

HurtPlayer()関数は正常に動作していますが、現在は Damage() メソッドに固定のリテラル値を渡しているため、その値を変更するにはコードを手動で変更する必要があります。

このレッスンでは、別の関数からの戻り値を使用して、HurtPlayer() 関数をより柔軟にする方法を学習します。

レッスン4では、プレイヤーの体力値に基づいて、条件式を使ってポーションのダメージや回復量を計算するコードの一部を取り上げました。

ここでは、その一部を CalculateDamage() という関数に切り出し、この関数は float 型の値を返します。

この返り値を定数に格納し、それを後に Damage() メソッドに渡すことで、HurtPlayer() 関数をより柔軟に操作することができます。

▼ まず、CalculateDamageという名前の関数を作成します。

関数内で float 型の 2 つの定数 MinHealthPotionDamageAmount 、また、float 型の変数 PlayerHealth も宣言しましょう。

 # ダメージ計算に関する定数の宣言
 CalculateDamage() : float = 
     # 最低限の体力値
     MinHealth : float = 1.0
     # ポーションのダメージ量
     PotionDamageAmount: float = 80.0
     # プレイヤーの体力値の変数宣言
     var PlayerHealth : float = 100.0

▼ 3つの値の1つを返す if … else if … else 式を作成します。

  • PlayerHealth が PotionDamageAmount より大きい場合は PotionDamageAmount
  • PlayerHealth が PotionDamageAmount より小さくて MinHealth より大きい場合は PlayerHealth - MinHealth
  • PlayerHealth が MinHealth と同じ場合は PlayerHealth
 # ダメージ量によってプレイヤーが倒れない場合は、そのダメージ量を実行します
 if (PlayerHealth > PotionDamageAmount):
     return PotionDamageAmount
 else if (PlayerHealth > MinHealth):
     # プレイヤーの体力値が低い場合は、もう一度チャンスを与えます
     return PlayerHealth - MinHealth
 else:
     # プレイヤーを倒します
     return PlayerHealth

上記は、CalculateDamage 関数内の一部で、プレイヤーの体力値に応じてダメージ量を計算するための条件式です。

まず、PlayerHealthPotionDamageAmount よりも大きい場合、つまりプレイヤーの体力値がポーションのダメージ量よりも大きい場合、ポーションのダメージ量を戻り値として返します。

これにより、プレイヤーがポーションによるダメージで倒れないようになります。

次に、PlayerHealthPotionDamageAmount よりも小さく、かつ MinHealth よりも大きい場合、つまりプレイヤーの体力値がポーションのダメージ量未満であり、かつ最低限の体力値以上の場合、再度チャンスを与えるため、プレイヤーの体力値から最低限の体力値を引いた値を戻り値として返します。

最後に、上記の条件に当てはまらない場合、つまりプレイヤーの体力値がポーションのダメージ量以下であり、かつ最低限の体力値と同じかそれ以下の場合、プレイヤーは倒れたと判断し、現在の体力値をそのまま戻り値として返します。

returnは、関数内で計算された結果や値を返すために使用されるキーワードです。

関数が呼び出された場所に対して値を返す役割を果たします。

あすか

▼ 便利な結果を返す関数を作成したので、その結果を格納する必要があります。

DamageToDo という名前の定数 float を宣言し、CalculateDamage() の戻り値で初期化します。

これを HurtPlayer() 関数に追加します。

 HurtPlayer() : void =
     Playspace : fort_playspace = GetPlayspace()
     AllPlayers : []player = Playspace.GetPlayers()
     if (FirstPlayer : player = AllPlayers[0]):
         if (FortniteCharacter : fort_character = FirstPlayer.GetFortCharacter[]):
             DamageToDo: float = CalculateDamage()
             FortniteCharacter.Damage(50.0)

▼ 最後に結果を使用します。

DamageToDo を引数として Damage() に渡します。

CalculateDamage() が返すものを正確に確認するために Print() を追加します。

 HurtPlayer() : void =
     Playspace : fort_playspace = GetPlayspace()
     AllPlayers : []player = Playspace.GetPlayers()
     if (FirstPlayer : player = AllPlayers[0]):
         if (FortniteCharacter : fort_character = FirstPlayer.GetFortCharacter[]):
             DamageToDo: float = CalculateDamage()
             Print("DamageToDo: {DamageToDo}")
             FortniteCharacter.Damage(DamageToDo)

Damage() メソッドを呼び出す際に、リテラル値ではなく CalculateDamage() 関数から返された値を使用しましょう。

 なぜ、CalculateDamage()なのか?

CalculateDamage() から返される値を使用することで、ダメージ量をプログラムの他の部分から制御可能にし、ゲームやアプリケーションの柔軟性と拡張性を高めることができるからです。

CalculateDamage()メソッド内でダメージ量を計算するロジックを実装しています。

このメソッドを修正することで、ダメージの計算方法を容易に変更することができるわけですね。

例えば、プレイヤーのレベルやスキルに基づいてダメージを計算するように変更することができます。

これにより、ゲームのバランス調整や新しいルールの追加など、ダメージの計算方法を自由に調整できます。

あすか

まとめ

UEFN Verse 結果を指定する まとめ

今回は、関数の結果を指定する方法について解説しました。

 今回のまとめ
  • 結果とは、関数を呼び出した際に得られるもの
  • コード ブロック 内では、最後の式が結果を生成する
  • 関数から取得する値の型を変更するには、関数シグネチャ の型を変更する
  • return は、その後に続く式から生成される値を提供するよう関数に指示するキーワード
  • 早期 return は、ブロックが終了する前に return キーワードが使用されると発生する
    • これにより、プログラムがコード ブロックをすぐに終了し、ブロック内の残りのコードが実行されることはない
  • void は、関数の値が他のどの場所でも使用されることがないことを示す型である
    • また、単に処理を実行する価値がないことを示す
    • void は結果を生成する必要がない関数の型に使用できる

また、今回の演習で扱ったコードは以下のとおりです。

 完全なスクリプト
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Fortnite.com/Playspaces }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }

hello_world_device := class(creative_device):

    # 実行中のゲームで仕掛けが開始されたときに実行します
    OnBegin<override>()<suspends>:void=

        HurtPlayer()
        Print("Player Hurt")

    CalculateDamage() : float = 
        MaxHealth : float = 100.0
        MinHealth : float = 1.0
        PotionDamageAmount: float = 80.0
        var PlayerHealth : float = 100.0

        # ダメージ量によってプレイヤーが倒れない場合は、そのダメージ量を実行します
        if (PlayerHealth > PotionDamageAmount):
            return PotionDamageAmount
        else if (PlayerHealth > MinHealth):
            # プレイヤーのヘルス値が低い場合は、もう一度チャンスを与えます
            return PlayerHealth - MinHealth
        else:
            # プレイヤーを倒します
            return PlayerHealth

    HurtPlayer() : void =
        Playspace: fort_playspace = GetPlayspace()
        AllPlayers: []player = Playspace.GetPlayers()
        if (FirstPlayer : player = AllPlayers[0]):
            if (FortniteCharacter : fort_character = FirstPlayer.GetFortCharacter[]):
                DamageToDo: float = CalculateDamage()
                Print("DamageToDo: {DamageToDo}")
                FortniteCharacter.Damage(DamageToDo)

次回は、入力、パラメータ、引数の仕組みについてやっていきます。

引き続き、がんばっていきましょう🔥

>> 【UEFNのVerse】関数でパラメータを定義して必要な結果を得る方法

【UEFNのVerse】関数でパラメータを定義して必要な結果を得る方法
【UEFNのVerse】関数でパラメータを定義して必要な結果を得る方法

続きを見る

※参考文献:Epic Games

  • この記事を書いた人
  • 最新記事

あすか(Asuka)

自己紹介:UEFNクリエイター兼ブロガー
Verse言語独学中 | UE・プログラミング・3Dモデリング完全初心者 | 備忘録として学習記録をブログに残しています。
■好きな言葉
徳は弧ならず必ず隣あり.
■ひとこと
まだまだ未熟者ですが、
よろしくお願いします。

-UEFN, Verse言語, メタバース
-, ,