http://steamcommunity.com/sharedfiles/filedetails/?id=879449506 引用元
私は個人的に可能な限り一般的な変数を避けます。 データを保持する必要がある場合、私はそれらを使用します。
たとえば、サンプルテーブルを参照する場合、「保存/読み込み」メモリの例には、カウンタの値を追跡するグローバル変数があります。
これらは高度ですが、コルーチンは短い待機、一時停止、遅延などを管理するのに最適です。通常、スクリプトを実行すると、ゲームの1つの「フレーム」内ですべて起動します。 コルーチンは、次のフレームまで実行を一時停止することができます。これらのポーズを連鎖させてスクリプトを待機させることができます。 これは、(オブジェクトが安静になるのを待つなどの)短い遅延の後に起こることを知っているものを待つためにも使用できます。 あなたはこれらをマスターする必要があると感じないでください。 特定の状況でのみ使用されるため、使用されている理由を理解している限り、問題はありません。
関数の名前を呼び出すのではなく、コルーチンを使用する場合は、startLuaCorotuineを使用して代わりにトリガします。
すべてのコルーチンは、終了時に正しく終了させるために、Tabletop Simulatorでreturn 1で終了する必要があります。
startLuaCoroutineを使用する場合、最初のパラメータはコルーチンスクリプトが見つかる場所(この例ではグローバルスクリプト)への参照です。
2番目のパラメータは関数名です。
この時点から、良いスクリプトを作成するための基本的な概念を十分に理解しておく必要があります。 今では、それらの概念を実践することを学ぶ必要があります。 私の意見では、それを管理する最善の方法は例で学ぶことです。 まだお持ちでない場合は、このガイドのWORKSHOP COMPANION TABLEを購読してください。
以下に続くのは、各例の背後にある概念とその動作の簡単な説明です。 サンプルの表では、各トークンにはスクリプトが保存されており、詳細なコメントが付いており、これらのツールの内部動作を説明しています。 彼らはまた彼らが何をすべきかに関する彼らの名前/説明に情報を持っています。
学習のこの時点では、すべての基本がカバーされているので、後は具体的な例や特定のLua関数(たとえば、ラウンド関数)をググることです。
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
3つの白いオブジェクト、正方形、長方形、三角形を含みます。
ボタンを押すと四角形が撤回され、オブジェクト上にある「Square」という名前で識別されます。 正方形だけを引っ張り出します。
--ボタン生成
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
これはあまり一般的ではありませんが、オブジェクトを何も生成しないようにすることができます。
ナレッジベースからいくつかの情報を検索する必要がありますが、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
タイマー機能では、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
Tabletop Simulatorでオブジェクトを配置するのはあなたが最もやることの1つであり、多くの場合、GUIDの管理に不便な方法や不可能な方法があります。 アイテムを見つける方法はさまざまですが、さまざまな方法で組み合わせてさまざまな結果を得ることができます。 しかし、彼らはすべてこれまで沸き起こっています。あなたが望むアイテムが一部である可能性のあるアイテムのプールを取得した後、いくつかの固有の識別情報を探しています。
これらの同じメソッドを、ナレッジベースに記載されている「メンバ変数」の多くで使用できます。 あなたが使用するものは、あなたがそれを使用している状況に100%依存しているので、柔軟性があります。
元に戻すまたはやり直しを実行するかテーブルを読み込むたびに、すべてのスクリプトが新たに開始されます。 したがって、グローバル変数を使用して数値をトラッキングしていた場合、[元に戻す]を押すと、グローバル変数がデフォルト値にリセットされます。
これがonSaveが活躍する場所です。 それはあなたがスクリプトの間にロードする間に覚えておきたいものをテーブルに入れることを可能にします。 次に、テーブルを次にロードすると、onLoad()中にその情報が取り出され、アクセスします。 これは非常に単純な関数であり、一部のスクリプトでは不可欠です。
個人的な助言の一部、私はスクリプトを書くときに常に最後のonSave()を残すことをお勧めします。 その理由は、スクリプトのバグのために情報が保存されることがあり、それを修正する必要があるため、追跡が面倒なことがあるからです。 私は通常、スクリプトをonSaveを使用するように設定しましたが、実際にそれをアクティブにしないと、私はそれが意図するように他のことをしているように感じます。
ランダムプレイヤー、アイテムなどを選択する際に重要です。テーブルから要素を選択したり、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()をシードとして使用することです。その後時々シードを変えます。このメソッドは、秒単位でしか使用されないので、このメソッドには注意する必要があります。がんばろう。