スクリプト4

http://steamcommunity.com/sharedfiles/filedetails/?id=879449506 引用元

・LUAスクリプト解説のパート2
warkshopにサンプルがUPされているhttp://steamcommunity.com/sharedfiles/filedetails/?id=879494019
 
 
Creating/Calling New Functions
コーディングの一般的なプラクティスは、別の関数を「呼び出す」ことです。 これらの関数の一部はAPIの一部です。 たとえば、print( "Word")を使用すると、その文字列をホストのチャットログに入れる関数が呼び出されます。 しかし、私たちは開発者が作成した機能に限らず、自分で作成することもできます。 これは、他の場所でプロセスを続けるか、情報を作成/変更/検索する独自の関数を作成することです。

作成する別の関数を呼び出すのは、関数の名前を作るのと同じくらい簡単です。
function onLoad() anotherFunction() end function anotherFunction() print("This will print on load") end

新しい関数にもパラメータを送ることができます。
function onLoad() printThisString("This will be printed by a custom function.") end function printThisString(stringToPrint) print(stringToPrint) end

関数を使用して作業を分離することもできます。 あなたがこれを行うことを選ぶかもしれない複数の理由があります。 繰り返すコードで使用することも、コードを読みやすくするために使用して、すべてを自分で実行しようとする大規模で膨大な機能を回避することもできます。 さらに、これらの関数は情報を「返す」ことができます。
function onLoad() local result = addTheseNumbers(2,3) print(result) --prints "5" end function addTheseNumbers (num1, num2) return num1 + num2 end

Returnは、実行すると自動的に関数を終了させるので、常にロジックの行の最後のステップにする必要があります。

それから、より大きな機能を持っているので、各ステップで何が行われているのかを追跡するのが難しく、混乱の原因となります。 これが問題であれば、大きな関数を小さな関数に分解することで問題を見つけるのに役立ちます。
 
 
Local/Global Variables
これまでは、コード全体に対して永続的で利用可能なグローバル変数しか扱っていませんでした。 たとえば、これはグローバル変数を作成します。
function onLoad() globalString = "I will always exist." doATestPrint() end function doATestPrint() print(globalString) --prints the string successfully end

しかし、ほとんどのアプリケーションでは、ローカル変数を使用することをお勧めします。 それらは変数が作成されているときに変数名の前に "local"という単語を置いて作成されます。 ローカル変数は作成された関数内にのみ存在します。 関数が終了すると、ローカル変数が忘れられます。 グローバル変数のみを使用する場合は、より長いスクリプトでは、複雑な変数名、間違った変数の上書き、古い変数の誤った使用などが考えられます。以下は、このローカル変数の違いの例です。
function onLoad() local localString = "I don't exist outside of this function." doATestPrint() end function doATestPrint() print(localString) --Will not print the string --Because that string doesn't exist in this function, only in onLoad end
しかし、コードをさまざまな機能に変えると、時々これらのローカル変数を通信して共有する方法が必要になります。 そのような場合は、ローカル変数を別の関数とパラメータとして送信して共有することができます。
function onLoad() local localString = "I will be passed to another function." doATestPrint(localString) end function doATestPrint() print(localString) --Will print successfully end

私は個人的に可能な限り一般的な変数を避けます。 データを保持する必要がある場合、私はそれらを使用します。

たとえば、サンプルテーブルを参照する場合、「保存/読み込み」メモリの例には、カウンタの値を追跡するグローバル変数があります。

 
 
Coroutines

これらは高度ですが、コルーチンは短い待機、一時停止、遅延などを管理するのに最適です。通常、スクリプトを実行すると、ゲームの1つの「フレーム」内ですべて起動します。 コルーチンは、次のフレームまで実行を一時停止することができます。これらのポーズを連鎖させてスクリプトを待機させることができます。 これは、(オブジェクトが安静になるのを待つなどの)短い遅延の後に起こることを知っているものを待つためにも使用できます。 あなたはこれらをマスターする必要があると感じないでください。 特定の状況でのみ使用されるため、使用されている理由を理解している限り、問題はありません。

関数の名前を呼び出すのではなく、コルーチンを使用する場合は、startLuaCorotuineを使用して代わりにトリガします。 すべてのコルーチンは、終了時に正しく終了させるために、Tabletop Simulatorでreturn 1で終了する必要があります。 startLuaCoroutineを使用する場合、最初のパラメータはコルーチンスクリプトが見つかる場所(この例ではグローバルスクリプト)への参照です。 2番目のパラメータは関数名です。
 

function onLoad() startLuaCoroutine(Global, "exampleCoroutine") end function exampleCoroutine() print("This will run right away, on load.") return 1 end

コルーチンの例はまったく中断しませんでした。 ポーズを追加したい場合は、コードcoroutine.yield(0)を実行します。 これは "降伏"し、コルーチンは次のフレームまで待ってから継続します。 したがって、この次の例では、200フレーム分が得られます。
function onLoad() startLuaCoroutine(Global, "exampleCoroutine") end function exampleCoroutine() print("This will run right away, on load.") for i=1, 200 do coroutine.yield(0) end print("This will run 200 frames after on load.") return 1 end
 
 
---BEGINNING OF EXAMPLES---

この時点から、良いスクリプトを作成するための基本的な概念を十分に理解しておく必要があります。 今では、それらの概念を実践することを学ぶ必要があります。 私の意見では、それを管理する最善の方法は例で学ぶことです。 まだお持ちでない場合は、このガイドのWORKSHOP COMPANION TABLEを購読してください。

以下に続くのは、各例の背後にある概念とその動作の簡単な説明です。 サンプルの表では、各トークンにはスクリプトが保存されており、詳細なコメントが付いており、これらのツールの内部動作を説明しています。 彼らはまた彼らが何をすべきかに関する彼らの名前/説明に情報を持っています。

学習のこの時点では、すべての基本がカバーされているので、後は具体的な例や特定のLua関数(たとえば、ラウンド関数)をググることです。

 
 
Example: takeObject()

takeObject()は、コンテナ(デッキまたはバッグ)からオブジェクトを取得する方法です。これは非常に一般的に使用されており、あなたが頼りになる多くのコアコンセプトが関連付けられています。私は特にあなたが学ぶことを望む2つがあります。

最初のものは、あなたが何をしたいのかを伝えるための関数パラメータを与えるという概念です。特定の名前付き要素(例:位置、回転など)を含むテーブルを作成し、それをtakeObjectに渡します。 (例えば、takeObject(parameters))。ナレッジベースは、どのようなパラメータ関数が受け入れることができるかを概説します

2番目は関数の "コールバック"部分です。関数の中のオブジェクトがロードされた後、他の関数を呼び出して動作することを意味する「コールバック」が可能な関数もあります。これは重要です。なぜなら、takeObjectを使用すると、オブジェクトがまだ表に物理的に存在しないため、すぐには特定のアクションを実行できないからです。だからあなたはそれをロックすることはできません、その色合いなどを設定するコールバックは、世界に読み込まれた後にそれらのアクションを実行することができます。コールバックを理解することは、takeObjectの使用後にオブジェクトを操作する上で不可欠です。

 

 

 

 

 

 

 

 

■exsample1の説明

3つの白いオブジェクト、正方形、長方形、三角形が含まれます。
ボタンを押すと、このバッグの最後のアイテムが引き出されます(最後に入れたもの、またはシャッフルした場合の「上のもの」)

■スクリプトの中身

--↓このスクリプトは、ゲーム、バッグ自体がロードされた時点で始動する。 という意味のスクリプト
function onLoad()
    --ボタンを作成する
    self.createButton({
        label="takeObject\nExample 1", click_function="buttonClick",--ラベルに描かれる文字、クリックしたときの動作=ボタンクリック
        function_owner=self, position={0,0.5,3}, --機能=自身、位置の指定
        height=1100, width=2000, font_size=380--ボタンのサイズ、フォントサイズ
    })
end

--ボタンを押されることによって始動する
function buttonClick(entity, color)
    -- ボタンで機能させると、
     --ボタンにはデフォルトのパラメータが発生するので、 私はそれらを(entity, color)と名付けました。
     --entityは、ボタンに付属する実体を示します。
         -- この場合、その実体は「自己」であり、バッグそのものを指します。
     --colorは文字列で、ボタンを押した人の色です
         --例えば "白プレイヤー"または "青プレイヤー"
     -- 使用していないので、定義する必要はありませんでした
     -- 代わりに関数buttonClick()

-- まず、オブジェクトをどこに配置したいのかを把握しましょう。
     -- バッグからZ方向に-5単位のところに出したいとします。
     -- まずは、バッグの位置を見つける必要があります。
    local pos = self.getPosition()

--↑セルフ=自身、このスクリプトを入れてるバッグ自体の位置を取得する

    - それからz軸で-5 unitz、Y軸で4単位増やす
    pos.y = pos.y + 4
    pos.z = pos.z - 5

- これはposを使ってバッグから物を取り出すものです
     - 位置は私たちが使うことができるただ一つの要素です。
     - それらのすべての知識ベースを参照してください。
    self.takeObject({position=pos})
end

■exsample2の説明

3つの白いオブジェクト、正方形、長方形、三角形を含みます。

ボタンを押すと四角形が撤回され、オブジェクト上にある「Square」という名前で識別されます。 正方形だけを引っ張り出します。

■スクリプトの中身
 
--ゲームが読み込まれ、このバッグが生成されたときに始動する↓
function onLoad()

    --ボタン生成
    self.createButton({
        label="takeObject\nExample 2", click_function="buttonClick",
        function_owner=self, position={0,0.5,3},
        height=1100, width=2000, font_size=380
    })
end

--ボタンを押したときに始動
function buttonClick()
    --これはこの関数の後半で使用される変数を設定しています
    local foundSquare = false
    --最初にバッグの中のオブジェクトのリストを取得する必要があります
    local objectsInBag = self.getObjects()
    --次に、forループを使ってこれらのエントリを調べ、1つを探します
    for _, object in ipairs(objectsInBag) do
        --「Square」という名前のエントリを探します。
        if object.name == "Square" then
            --見つかった場合は、takeObjectを使用する必要があります
             -- 私たちはまずポジションを取得します。これはバッグのポジションを使用する予定です
            local pos = self.getPosition()
            --次に、z単位で-5単位、Y単位で4単位を移動します
            pos.y = pos.y + 4
            pos.z = pos.z - 5

-- 今はtakeObjectを使用します。 私はそれにパラメータを与えます
             - それを与えるGUIDは、この特定のオブジェクトをバッグから引き出します
             - [[それをコールバックすると、コードの後にオブジェクトを実行することができます
                 世界の中に生まれました。 単に走ろうとしたら
                 コードを取得するためにtakeObjectを使用しているので、コードは存在しません
                 世界ではまだ(生まれていない)変更を適用することはできません。

コールバックとコールバックの両方を確立します。 コールバックは関数のNAMEであり、所有者はその場所です。]]

            self.takeObject({
                position=pos, guid=object.guid,
                callback="afterSpawn", function_owner=self
            })
            --Set foundSquare to true, to indicate we did find the square.
            foundSquare = true
            --We only want it to find 1 Square per button press
            --Break will end the for loop here, preventing multiple returns
            break
        end
    end

    --今度はfoundSquareをチェックして、forループが正方形を見つけたかどうかを調べる
    if foundSquare == false then
        broadcastToAll("There was no object named 'Square' in the bag.", {1,1,1})
    end
end

--これはコールバック関数で、takeObjectを使用したときにトリガされます。
--生成されたエンティティへの参照があることに注意してください。
function afterSpawn(spawnedObject)
    --これは、オブジェクトをロックし、色、名前などを変更する方法です
    spawnedObject.lock()
end

 
 
 
Example: spawnObject()

これはあまり一般的ではありませんが、オブジェクトを何も生成しないようにすることができます。 ナレッジベースからいくつかの情報を検索する必要がありますが、takeObjectより複雑ではありません。 それをtakeObjectと考えると、薄い空気から空白のスレートを取っています。あなたが望むものを伝えるのはあなた次第です。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

■スクリプト説明

「Spawn Die」ボタンを押すと死ぬことになります。 ダイズを生成します。

「Spawn Custom Model」を押すと、ダイのように動作するカスタムモデルセットが生成されます。

ほとんどのものはspawnObjectで作成できます。 デッキを除く(現在)。

■スクリプト内容

--Runs when bags spawn in when the map is loaded
function onLoad()
    --Creates the 2 buttons
    self.createButton({
        label="Spawn Die", click_function="buttonClick1",
        function_owner=self, position={0.8,0.1,-0.4},
        height=300, width=700, font_size=100
    })
    self.createButton({
        label="Spawn\nCustom Model", click_function="buttonClick2",
        function_owner=self, position={0.8,0.1,0.4},
        height=300, width=700, font_size=100
    })
end

--This runs when the button 1 on this object is clicked
--It will spawn a regular, generic die.
function buttonClick1()
    --We get the position of the tool first. We use this to place the item.
    --You can place it anywhere you like, I chose to place it near the tool.
    local toolPos = self.getPosition()
    --Spawn object takes parameters.
    --The available parameters are found in the knowledge base.
    --See the API page and the Spawnable Objects page.
    --type indicates what will be spawned, position indicates where
    spawnObject({
        type="Die_6",
        position={toolPos.x-2, toolPos.y+2, toolPos.z-3}
    })
end

--This runs when the button 2 on this object is clicked
--It will spawn a custom model set to act like a die
function buttonClick2()
    --Again, we will place it near the tool, so we need the tool's position
    local toolPos = self.getPosition()
    --This time there are 2 steps. First is spawning a custom model.
    --We are also making a reference to the object we are spawning.
    local obj = spawnObject({
        type="Custom_Model",
        position={toolPos.x+2, toolPos.y+2, toolPos.z-3},
        scale={0.5,0.5,0.5} --(shrinking it down a bit)
    })
    --Then we need to apply the object, material and properties that make it
    --We do this by applying setCustomObject to that reference (obj) we made
    --Again, this has many parameters you can feed it, KB has them all.
    obj.setCustomObject({
        type=2,
        mesh="http://pastebin.com/raw/CS2JYCqP",
        diffuse="http://i.imgur.com/AOJ50cH.jpg",
        specular_intensity=0
    })
end

 
 
Example: Timer

タイマー機能では、X時間後に機能をトリガーすることができます。 タイマにはUNIQUE識別子が必要です。 使用する名前は、表のANYコードの変数では共有できません。 この制限のため、タイマーの作成時にオブジェクトのGUIDを使用するのが一般的です。そのGUIDは一意である必要があるためです。

現在、卓上シミュレータのタイマーは、コードが停止/削除された場合でも実行され続けます。 したがって、実行中の定期的なタイマーがある場合は、そのコードのインスタンスを終了すると、実行を継続し、エラーをスローします。 取り消しやテーブルからの読み込みを行うと、アクションが実行されたときにタイマーが実行されていた場合にも、これらのタイマーエラーが発生します。 これはTTSのバグです。 ナレッジベースでは、タイマーを自動的に繰り返すオプションが表示されます。 このバグが将来修正されるまで、私はそれを使用しないことをお勧めします。

 

 

 

 

 

 

 

 

 

 

 

 

■スクリプト説明

This button, when clicked, starts a 3 second timer. While it is running, the timer turns red. Clicking the button again during this time will cause a warning message to print on your screen.

The timer will "Ding" when it ends, as well as turn the tool green again.

■スクリプト内容

--Runs when bags spawn in when the map is loaded
function onLoad()
    --Creates the button
    self.createButton({
        label="Timer\nExample", click_function="buttonClick",
        function_owner=self, position={0.8,0.1,0},
        height=500, width=700, font_size=150
    })
    --Creates a variable we use to track if the timer is currently running
    timerIsRunning = false
    --Set the object's color to green
    self.setColorTint({0,1,0})
end

--This runs when the button on this object is clicked
function buttonClick()
    --This check will determine if the timer has started yet, preventing overlap
    if timerIsRunning == true then
        --Displays an error message on screen
        broadcastToAll("Timer is already running.", {1,1,1})
    else
        --These are the parameters we will feed to the timer to start it
        local params = {
            --This is the "name" of the timer.
            --It must be unique, no other variable anywhere can have its name
            --To ensure this, I attach this object's GUID to that name
            identifier = "aUniqueTimerName"..self.getGUID(),
            --The name of the function the timer activates when it hits 0
            function_name = "timerRunsOut",
            --Where that function can be found
            function_owner = self,
            --How long, in seconds, the timer will run
            delay = 3
        }
        --Using those params to the timer creation to start the clock
        Timer.create(params)
        --Activating our variable which tracks if the timer is running
        timerIsRunning = true
        --Change the object's color to red
        self.setColorTint({1,0,0})
    end
end

--This runs after the timer has run
function timerRunsOut()
    --As good practice, I always "delete" the timer.
    --This shouldn't be necessary, but currently it can help avoid some bugs
    Timer.destroy("aUniqueTimerName"..self.getGUID())
    --We turn timerIsRunning back off
    timerIsRunning = false
    --And change the color back to green
    self.setColorTint({0,1,0})
    --Broadcast "Ding"
    broadcastToAll("Ding!", {0,1,0})
end

 

 

 
 
Example: Locating Objects

Tabletop Simulatorでオブジェクトを配置するのはあなたが最もやることの1つであり、多くの場合、GUIDの管理に不便な方法や不可能な方法があります。 アイテムを見つける方法はさまざまですが、さまざまな方法で組み合わせてさまざまな結果を得ることができます。 しかし、彼らはすべてこれまで沸き起こっています。あなたが望むアイテムが一部である可能性のあるアイテムのプールを取得した後、いくつかの固有の識別情報を探しています。

これらの同じメソッドを、ナレッジベースに記載されている「メンバ変数」の多くで使用できます。 あなたが使用するものは、あなたがそれを使用している状況に100%依存しているので、柔軟性があります。

 
 
Example: onSave()

元に戻すまたはやり直しを実行するかテーブルを読み込むたびに、すべてのスクリプトが新たに開始されます。 したがって、グローバル変数を使用して数値をトラッキングしていた場合、[元に戻す]を押すと、グローバル変数がデフォルト値にリセットされます。

これがonSaveが活躍する場所です。 それはあなたがスクリプトの間にロードする間に覚えておきたいものをテーブルに入れることを可能にします。 次に、テーブルを次にロードすると、onLoad()中にその情報が取り出され、アクセスします。 これは非常に単純な関数であり、一部のスクリプトでは不可欠です。

個人的な助言の一部、私はスクリプトを書くときに常に最後のonSave()を残すことをお勧めします。 その理由は、スクリプトのバグのために情報が保存されることがあり、それを修正する必要があるため、追跡が面倒なことがあるからです。 私は通常、スクリプトをonSaveを使用するように設定しましたが、実際にそれをアクティブにしないと、私はそれが意図するように他のことをしているように感じます。

 
 
Example: math.random()

ランダムプレイヤー、アイテムなどを選択する際に重要です。テーブルから要素を選択したり、RGBなどのランダムな色を選択したりするのに使用できます。 math.random()にパラメータを指定しなかった場合は、0と1の間の数値が選択されます(例:0.24531)。 2つのパラメータを指定した場合は、それらを床/天井の値として使用して選択します。例:math.random(1,3)は、整数(1,2または3)が返される結果になります。

しかし、スクリプトで本当に乱数を得るのはちょっと難しいかもしれません。それらが生成される方法は、「種」の数を基にした数式で計算されます。このシード値は、math.randomseed(numberhere)で設定できます。 numberhereにnumber 1を使用してからmath.random()を実行すると、結果が得られます。 randomseedをここに再度設定し、別のmath.randomを実行すると、同じ結果が得られます。それはちょうどその式に基づいているからです。

私はこの問題を回避するのに完璧なことがないので、異なるプレイヤーはすべて異なる順序で異なる乱数を得ることができますが、私の例ではよく使うトリックをいくつか挙げました。そのうちの1つは、ホストPC上の現在の時刻であるos.time()をシードとして使用することです。その後時々シードを変えます。このメソッドは、秒単位でしか使用されないので、このメソッドには注意する必要があります。がんばろう。

 

タグ:

+ タグ編集
  • タグ:
最終更新:2017年07月06日 18:02